Formula and their conversion to HGraph
This section covers examples of common financial formulas and how they can be represented in HGraph.
For the conversion of formulas to HGraph, we use the following definitions:
is a time-series of TIME_TYPE values, which can be either date or datetime. This is expected
to tick with a constant frequency with respect to values being processed. For example when we are pricing this should
tick with priceable days. The expected use of this to indicate current value or previous values in the form of:
previous price:

current price:
.
This works with a lag operator where the
represents how many ticks of the TIME_TYPE time-series
to delay the value by. For example, lag(price, i, t).
Note
This library largely focuses on the simplified view of computations, but the hg_oap library provides more
robust solutions to computing prices where dimension units are included with all numbers. This improves the
quality of the results as it handles conversions and unit alignment. It is easy to confuse an annual rate
with a daily rate when we do not track units in computations, however, tracking units on computations can also
add addition expense and complexity. This package is focused on more common patterns followed in the systematic
trading community, which tend to make more assumptions of the data (such as pricing in USD, etc.).
However, it is possible to apply all the techniques in this library to the price tooling provided by the
hg_oap library.
Simple Return

where:
is the price at time 
is the price at time
this effectively represents the periodicity of the computation
is the return at time 
@graph
def simple_return(p: TS[float], t: TS[TIME_TYPE]) -> TS[float]:
return (p / lag(p, 1, t) - 1.0
Adjusted Returns (for time-period)

where:
is the number of periods to convert from the shorter to longer period, in this case the number of trading days in a year.
is the return of the period to be converted at time
, in this case daily.
is the return at time
scaled to the period of interest (in this case annual).
This can be made a bit more generic by using the following formula:

where:
is number of periods of the shorter in time to the longer period.
is the longer time-period (e.g. annual)
is the shorter time-period (e.g. daily)
@graph
def adjusted_return(r: TS[float], n: TS[float]) -> TS[float]:
return (1.0 + r) ** n - 1.0
This approach also works when converting from a longer period to a shorter period, for example:

where:
is
is the fraction of days in a year.
Excess Returns
This is the comparison of returns vs a risk-free benchmark. This is typically a comparison to a rate such as returns of T-Bills, Overnight Indexed Swap (OIS), etc. Often the Secure Overnight Finance Rate (SOFR) is used as a proxy for a risk-free rate.

where:
is the return at time 
is the risk-free rate at time 
is the excess return at time 
Note, that the periods of the returns must align.
@graph
def excess_return(r: TS[float], rf: TS[float]) -> TS[float]:
return r - rf
A more specific example of this may be when using SOFR as the risk-free rate and a daily return as described above, the code may look something like this:
@graph
def my_computation():
t = business_day("MyInstrument")
p = price_in_dollars("MyInstrument")
r_my_inst = simple_return(p, t)
r_sofr = returns_in_dollars("SOFR") # This is an annual return
r_excess = excess_return(r_my_inst, adjusted_return(r_sofr, 1.0/252.0))
Resulting in a daily excess return.

is the return at time
is the mean of the excess return at time
is the standard deviation of the returns at time
) we need an amount of history. There are a couple of techniques
to compute this, but the most common is to use a rolling window. Note, we should align the window with
the samples used to compute the mean as well.