pyqstrat package¶
Submodules¶
pyqstrat.pq_utils module¶
- class pyqstrat.pq_utils.Paths(base_path=None)[source]¶
Bases:
object
Conventions for where to read / write data and reports
- pyqstrat.pq_utils.bootstrap_ci(a, ci_level=0.95, n=1000, func=<function mean>)[source]¶
Non parametric bootstrap for confidence intervals :type a:
ndarray
:param a: The data to bootstrap from :type ci_level:float
:param ci_level: The confidence interval level, e.g. 0.95 for 95%. Default 0.95 :type n:int
:param n: Number of boostrap iterations. Default 1000 :type func:Callable
[[ndarray
],ndarray
] :param func: The function to use, e.g np.mean or np.median. Default np.mean- Return type
Tuple
[float
,float
]- Returns
A tuple containing the lower and upper ci
>>> np.random.seed(0) >>> x = np.random.uniform(high=10, size=100000) >>> assert np.allclose(bootstrap_ci(x), (4.9773159, 5.010328))
- pyqstrat.pq_utils.day_of_week_num(a)[source]¶
From https://stackoverflow.com/questions/52398383/finding-day-of-the-week-for-a-datetime64 Get day of week for a numpy array of datetimes Monday is 0, Sunday is 6
- Parameters
a (
Union
[datetime64
,ndarray
]) – numpy datetime64 or array of datetime64- Returns
Monday is 0, Sunday is 6
- Return type
int or numpy ndarray of int
>>> day_of_week_num(np.datetime64('2015-01-04')) 6
- pyqstrat.pq_utils.get_empty_np_value(np_dtype)[source]¶
Get empty value for a given numpy datatype >>> a = np.array([‘2018-01-01’, ‘2018-01-03’], dtype = ‘M8[D]’) >>> get_empty_np_value(a.dtype) numpy.datetime64(‘NaT’)
- Return type
Any
- pyqstrat.pq_utils.has_display()[source]¶
If we are running in unit test mode or on a server, then don’t try to draw graphs, etc.
- Return type
bool
- pyqstrat.pq_utils.in_ipython()[source]¶
Whether we are running in an ipython (or Jupyter) environment
- Return type
bool
- pyqstrat.pq_utils.infer_compression(input_filename)[source]¶
Infers compression for a file from its suffix. For example, given “/tmp/hello.gz”, this will return “gzip” >>> infer_compression(“/tmp/hello.gz”) ‘gzip’ >>> infer_compression(“/tmp/abc.txt”) is None True
- Return type
Optional
[str
]
- pyqstrat.pq_utils.infer_frequency(timestamps)[source]¶
Returns most common frequency of date differences as a fraction of days :type timestamps:
ndarray
:param timestamps: A numpy array of monotonically increasing datetime64>>> timestamps = np.array(['2018-01-01 11:00:00', '2018-01-01 11:15:00', '2018-01-01 11:30:00', '2018-01-01 11:35:00'], dtype = 'M8[ns]') >>> print(round(infer_frequency(timestamps), 8)) 0.01041667
- Return type
float
- pyqstrat.pq_utils.is_newer(filename, ref_filename)[source]¶
whether filename ctime (modfication time) is newer than ref_filename or either file does not exist >>> import time >>> import tempfile >>> temp_dir = tempfile.gettempdir() >>> touch(f’{temp_dir}/x.txt’) >>> time.sleep(0.1) >>> touch(f’{temp_dir}/y.txt’) >>> is_newer(f’{temp_dir}/y.txt’, f’{temp_dir}/x.txt’) True >>> touch(f’{temp_dir}/y.txt’) >>> time.sleep(0.1) >>> touch(f’{temp_dir}/x.txt’) >>> is_newer(f’{temp_dir}/y.txt’, f’{temp_dir}/x.txt’) False
- Return type
bool
- pyqstrat.pq_utils.linear_interpolate(a1, a2, x1, x2, x)[source]¶
>>> assert(linear_interpolate(3, 4, 8, 10, 8.9) == 3.45) >>> assert(linear_interpolate(3, 3, 8, 10, 8.9) == 3) >>> assert(np.isnan(linear_interpolate(3, 4, 8, 8, 8.9))) >>> x = linear_interpolate( ... np.array([3., 3.]), ... np.array([4., 3.]), ... np.array([8., 8.]), ... np.array([10, 8.]), ... np.array([8.9, 8.])) >>> assert(np.allclose(x, np.array([3.45, 3.])))
- Return type
Union
[ndarray
,float
]
- pyqstrat.pq_utils.millis_since_epoch(dt)[source]¶
Given a python datetime, return number of milliseconds between the unix epoch and the datetime. Returns a float since it can contain fractions of milliseconds as well >>> millis_since_epoch(datetime.datetime(2018, 1, 1)) 1514764800000.0
- Return type
float
- pyqstrat.pq_utils.monotonically_increasing(array)[source]¶
Returns True if the array is monotonically_increasing, False otherwise
>>> monotonically_increasing(np.array(['2018-01-02', '2018-01-03'], dtype = 'M8[D]')) True >>> monotonically_increasing(np.array(['2018-01-02', '2018-01-02'], dtype = 'M8[D]')) False
- Return type
bool
- pyqstrat.pq_utils.nan_to_zero(array)[source]¶
Converts any nans in a numpy float array to 0
- Return type
ndarray
- pyqstrat.pq_utils.np_bucket(a, buckets, default_value=0, side='mid')[source]¶
Given a numpy array and a sorted list of buckets, assign each element to a bucket.
- Parameters
a (np.ndarray) – The numpy array of values
buckets (
List
[Any
]) – (list) List of bucketsdefault_value – Used when we cannot assign an element to any bucket if side is ‘left’ or ‘right’
side (str) – If set to mid, we use the midpoint between buckets to assign elements ‘left’, assignment <= element ‘right’, assignment >= element Default: ‘mid’
- Return type
ndarray
- Returns
np.ndarray of same length as a
>>> a = np.array([1, 5, 18, 3, 6, 10, 4]) >>> buckets = [4, 8, 12] >>> assert np.alltrue(np_bucket(a, buckets, side='left') == np.array([0, 4, 12, 0, 4, 8, 4])) >>> assert np.alltrue(np_bucket(a, buckets, default_value=25, side='right') == np.array([4, 8, 25, 4, 8, 12, 4])) >>> assert(np.alltrue(np_bucket(a, buckets) == np.array([4, 4, 12, 4, 8, 12, 4])))
- pyqstrat.pq_utils.np_find_closest(a, v)[source]¶
From https://stackoverflow.com/questions/8914491/finding-the-nearest-value-and-return-the-index-of-array-in-python Find index of closest value to array v in array a. Returns an array of the same size as v a must be sorted >>> assert(all(np_find_closest(np.array([3, 4, 6]), np.array([4, 2])) == np.array([1, 0])))
- Return type
Union
[int
,ndarray
]
- pyqstrat.pq_utils.np_get_index(array, value)[source]¶
Get index of a value in a numpy array. Returns -1 if the value does not exist.
- Return type
int
- pyqstrat.pq_utils.np_inc_dates(dates, num_days=1)[source]¶
Increment the given date array so each cell gets the next higher value in this array >>> dates = np.array([‘2021-06-01’, ‘2021-06-01’, ‘2021-08-01’, ‘2021-04-01’], dtype=’M8[D]’) >>> check = np.array([dates[2], dates[2], np.datetime64(‘nat’), dates[0]]) >>> assert np.array_equal(np_inc_dates(dates, 1), … np.array([‘2021-08-01’, ‘2021-08-01’, ‘NaT’, ‘2021-06-01’], dtype=’M8[D]’), equal_nan=True) >>> assert np.array_equal(np_inc_dates(dates, 2), … np.array([‘NaT’, ‘NaT’, ‘NaT’, ‘2021-08-01’], dtype=’M8[D]’), equal_nan=True) >>> assert np.array_equal(np_inc_dates(dates, -1), … np.array([‘2021-04-01’, ‘2021-04-01’, ‘2021-06-01’, ‘NaT’], dtype=’M8[D]’), equal_nan=True) >>> assert np.array_equal(np_inc_dates(dates, -2), … np.array([‘NaT’, ‘NaT’, ‘2021-04-01’, ‘NaT’], dtype=’M8[D]’), equal_nan=True)
- Return type
ndarray
- pyqstrat.pq_utils.np_parse_array(s, dtype=<class 'float'>)[source]¶
Create a 1 or 2 d numpy array from a string that looks like: [[2. 5. 3. 0. 0.]
[3. 5. 0. 4. 3.]]
or [2. 5. 3. 0. 8.]
>>> x = np_parse_array('[[2. 5. 3. 0. 0.]\n [3. 5. 0. 4. 3.]]') >>> assert np.allclose(x, np.array([[2., 5., 3., 0., 0.], [3., 5., 0., 4., 3.]])) >>> x = np_parse_array('[3 4. 5]') >>> assert np.allclose(x, np.array([3, 4., 5]))
- Return type
ndarray
- pyqstrat.pq_utils.np_rolling_window(a, window)[source]¶
For applying rolling window functions to a numpy array See: https://stackoverflow.com/questions/6811183/rolling-window-for-1d-arrays-in-numpy >>> print(np.std(np_rolling_window(np.array([1, 2, 3, 4]), 2), 1)) [0.5 0.5 0.5]
- Return type
ndarray
- pyqstrat.pq_utils.np_round(a, clip)[source]¶
Round all elements in an array to the nearest clip
- Parameters
a (
ndarray
) – array with elements to roundclip (
float
) – rounding value
>>> np_round(15.8, 0.25) 15.75
- pyqstrat.pq_utils.np_uniques(arrays)[source]¶
Given a list of numpy arrays that may have different datatype, generate a structured numpy array with sorted, unique elements from that list >>> array1 = np.array([‘2018-01-02’, ‘2018-01-03’, ‘2018-01-02’, ‘2018-01-03’], dtype=’M8[D]’) >>> array2 = np.array([‘P’, ‘P’, ‘P’, ‘C’]) >>> x = np_uniques([array1, array2]) >>> assert len(x) == 3 >>> assert x[0][0] == np.datetime64(‘2018-01-02’) >>> assert x[0][1] == ‘P’
- Return type
ndarray
- pyqstrat.pq_utils.percentile_of_score(a)[source]¶
For each element in a, find the percentile of a its in. From stackoverflow.com/a/29989971/5351549 Like scipy.stats.percentileofscore but runs in O(n log(n)) time. >>> a = np.array([4, 3, 1, 2, 4.1]) >>> percentiles = percentile_of_score(a) >>> assert(all(np.isclose(np.array([ 75., 50., 0., 25., 100.]), percentiles)))
- Return type
Optional
[ndarray
]
- pyqstrat.pq_utils.remove_dups(lst, key_func=None)[source]¶
Remove duplicates from a list :type lst:
Sequence
[Any
] :param lst: list to remove duplicates from :type key_func:Optional
[Callable
[[Any
],Any
]] :param key_func: A function that takes a list element and converts it to a key for detecting dups- Return type
MutableSequence
[Any
]- Returns
A list with duplicates removed. This is stable in the sense that original list elements will retain their order
>>> print(remove_dups(['a', 'd', 'a', 'c'])) ['a', 'd', 'c'] >>> print(remove_dups(['a', 'd', 'A'])) ['a', 'd', 'A'] >>> print(remove_dups(['a', 'd', 'A'], key_func = lambda e: e.upper())) ['a', 'd']
- pyqstrat.pq_utils.resample_trade_bars(df, sampling_frequency, resample_funcs=None)[source]¶
Downsample trade bars using sampling frequency
- Parameters
df (pd.DataFrame) – Must contain an index of numpy datetime64 type which is monotonically increasing
sampling_frequency (str) – See pandas frequency strings
str (resample_funcs (dict of) – int): a dictionary of column name -> resampling function for any columns that are custom defined. Default None. If there is no entry for a custom column, defaults to ‘last’ for that column
- Returns
Resampled dataframe
- Return type
pd.DataFrame
>>> import math >>> df = pd.DataFrame({'date': np.array(['2018-01-08 15:00:00', '2018-01-09 13:30:00', '2018-01-09 15:00:00', '2018-01-11 15:00:00'], dtype = 'M8[ns]'), ... 'o': np.array([8.9, 9.1, 9.3, 8.6]), ... 'h': np.array([9.0, 9.3, 9.4, 8.7]), ... 'l': np.array([8.8, 9.0, 9.2, 8.4]), ... 'c': np.array([8.95, 9.2, 9.35, 8.5]), ... 'v': np.array([200, 100, 150, 300]), ... 'x': np.array([300, 200, 100, 400]) ... }) >>> df['vwap'] = 0.5 * (df.l + df.h) >>> df.set_index('date', inplace = True) >>> df = resample_trade_bars(df, sampling_frequency = 'D', resample_funcs={'x': lambda df, ... sampling_frequency: df.x.resample(sampling_frequency).agg(np.mean)}) >>> assert(len(df) == 4) >>> assert(math.isclose(df.vwap.iloc[1], 9.24)) >>> assert(np.isnan(df.vwap.iloc[2])) >>> assert(math.isclose(df.l[3], 8.4))
- pyqstrat.pq_utils.resample_ts(dates, values, sampling_frequency)[source]¶
Downsample a tuple of datetimes and value arrays using sampling frequency, using the last value if it does not exist at the bin edge. See pandas.Series.resample
- Parameters
dates (
ndarray
) – a numpy datetime64 arrayvalues (
ndarray
) – a numpy arraysampling_frequency (
str
) – See pandas frequency strings
- Return type
Tuple
[ndarray
,ndarray
]- Returns
Resampled tuple of datetime and value arrays
- pyqstrat.pq_utils.resample_vwap(df, sampling_frequency)[source]¶
Compute weighted average of vwap given higher frequency vwap and volume
- Return type
Optional
[ndarray
]
- pyqstrat.pq_utils.series_to_array(series)[source]¶
Convert a pandas series to a numpy array. If the object is not a pandas Series return it back unchanged
- Return type
ndarray
- pyqstrat.pq_utils.set_defaults(df_float_sf=9, df_display_max_rows=200, df_display_max_columns=99, np_seterr='raise', mpl_figsize=(8, 6), jupyter_multiple_display=True)[source]¶
Set some display defaults to make it easier to view dataframes and graphs.
- Parameters
df_float_sf (
int
) – Number of significant figures to show in dataframes (default 4). Set to None to use pandas defaultsdf_display_max_rows (
int
) – Number of rows to display for pandas dataframes when you print them (default 200). Set to None to use pandas defaultsdf_display_max_columns (
int
) – Number of columns to display for pandas dataframes when you print them (default 99). Set to None to use pandas defaultsnp_seterr (
str
) – Error mode for numpy warnings. See numpy seterr function for details. Set to None to use numpy defaultsmpl_figsize (
Tuple
[int
,int
]) – Default figure size to use when displaying matplotlib plots (default 8,6). Set to None to use defaultsjupyter_multiple_display – If set, and you have multiple outputs in a Jupyter cell, output will contain all of them. Default True
- Return type
None
- pyqstrat.pq_utils.shift_np(array, n, fill_value=None)[source]¶
Similar to pandas.Series.shift but works on numpy arrays.
- Parameters
array (
ndarray
) – The numpy array to shiftn (
int
) – Number of places to shift, can be positive or negativefill_value (
Optional
[Any
]) – After shifting, there will be empty slots left in the array. If set, fill these with fill_value. If fill_value is set to None (default), we will fill these with False for boolean arrays, np.nan for floats
- Return type
ndarray
- pyqstrat.pq_utils.str2date(s)[source]¶
Converts a string like “2008-01-15 15:00:00” to a numpy datetime64. If s is not a string, return s back
- Return type
Optional
[datetime64
]
- pyqstrat.pq_utils.strtup2date(tup)[source]¶
Converts a string tuple like (“2008-01-15”, “2009-01-16”) to a numpy datetime64 tuple. If the tuple does not contain strings, return it back unchanged
- Return type
Tuple
[Optional
[datetime64
],Optional
[datetime64
]]
- pyqstrat.pq_utils.to_csv(df, file_name, index=False, compress=False, *args, **kwargs)[source]¶
Creates a temporary file then renames to the permanent file so we don’t have half written files. Also optionally compresses using the xz algorithm
- Return type
None
pyqstrat.pq_types module¶
- class pyqstrat.pq_types.Contract[source]¶
Bases:
object
- static clear()[source]¶
When running Python interactively you may create a Contract with a given symbol multiple times because you don’t restart Python therefore global variables are not cleared. This function clears global Contracts
- Return type
None
- contract_group: ContractGroup¶
- contracts_by_symbol: Mapping[str, Contract]¶
A contract such as a stock, option or a future that can be traded
- static create(symbol, contract_group, expiry=None, multiplier=1.0, properties=None)[source]¶
- Parameters
symbol (
str
) – A unique string reprenting this contract. e.g IBM or ESH9contract_group (
ContractGroup
) – We sometimes need to group contracts for calculating PNL, for example, you may have a strategy which has 3 legs, a long option, a short option and a future or equity used to hedge delta. In this case, you will be trading different symbols over time as options and futures expire, but you may want to track PNL for each leg using a contract group for each leg. So you could create contract groups ‘Long Option’, ‘Short Option’ and ‘Hedge’ and assign contracts to these.expiry (
Union
[datetime64
,datetime
,None
]) – In the case of a future or option, the date and time when the contract expires. For equities and other non expiring contracts, set this to None. Default None.multiplier (
float
) – If the market price convention is per unit, and the unit is not the same as contract size, set the multiplier here. For example, for E-mini contracts, each contract is 50 units and the price is per unit, so multiplier would be 50. Default 1properties (
Optional
[SimpleNamespace
]) – Any data you want to store with this contract. For example, you may want to store option strike. Default None
- Return type
- expiry: Optional[datetime64]¶
- multiplier: float¶
- properties: SimpleNamespace¶
- symbol: str¶
- class pyqstrat.pq_types.ContractGroup[source]¶
Bases:
object
A way to group contracts for figuring out which indicators, rules and signals to apply to a contract and for PNL reporting
- static clear()[source]¶
When running Python interactively you may create a ContractGroup with a given name multiple times because you don’t restart Python therefore global variables are not cleared. This function clears global ContractGroups
- Return type
None
- name: str¶
- class pyqstrat.pq_types.LimitOrder(contract, timestamp, qty, limit_price, reason_code='none', properties=None, status='open')[source]¶
Bases:
Order
- __init__(contract, timestamp, qty, limit_price, reason_code='none', properties=None, status='open')[source]¶
- Parameters
contract (
Contract
) – The contract this order is fortimestamp (
datetime64
) – Time the order was placedqty (
float
) – Number of contracts or shares. Use a negative quantity for sell orderslimit_price (
float
) – Limit price (float)reason_code (
str
) – The reason this order was created. Prefer a predefined constant from the ReasonCode class if it matches your reason for creating this order. Default Noneproperties (
Optional
[SimpleNamespace
]) – Any order specific data we want to store. Default Nonestatus (
str
) – Status of the order, “open”, “filled”, etc. (default “open”)
- class pyqstrat.pq_types.MarketOrder(contract, timestamp, qty, reason_code='none', properties=None, status='open')[source]¶
Bases:
Order
- __init__(contract, timestamp, qty, reason_code='none', properties=None, status='open')[source]¶
- Parameters
contract (
Contract
) – The contract this order is fortimestamp (
datetime64
) – Time the order was placedqty (
float
) – Number of contracts or shares. Use a negative quantity for sell ordersreason_code (
str
) – The reason this order was created. Prefer a predefined constant from the ReasonCode class if it matches your reason for creating this order. Default Noneproperties (
Optional
[SimpleNamespace
]) – Any order specific data we want to store. Default Nonestatus (
str
) – Status of the order, “open”, “filled”, etc. Default “open”
- class pyqstrat.pq_types.OrderStatus[source]¶
Bases:
object
Enum for order status
- FILLED = 'filled'¶
- OPEN = 'open'¶
- class pyqstrat.pq_types.Price(timestamp, bid, ask, bid_size, ask_size, valid=True, properties=None)[source]¶
Bases:
object
>>> price = Price(datetime.datetime(2020, 1, 1), 15.25, 15.75, 189, 300) >>> print(price) 15.25@189/15.75@300 >>> price.properties = SimpleNamespace(delta = -0.3) >>> price.valid = False >>> print(price) 15.25@189/15.75@300 delta: -0.3 invalid >>> print(price.mid()) 15.5
- ask: float¶
- ask_size: int¶
- bid: float¶
- bid_size: int¶
- properties: Optional[SimpleNamespace] = None¶
- timestamp: datetime¶
- valid: bool = True¶
- class pyqstrat.pq_types.ReasonCode[source]¶
Bases:
object
A class containing constants for predefined order reason codes. Prefer these predefined reason codes if they suit the reason you are creating your order. Otherwise, use your own string.
- BACKTEST_END = 'backtest end'¶
- ENTER_LONG = 'enter long'¶
- ENTER_SHORT = 'enter short'¶
- EXIT_LONG = 'exit long'¶
- EXIT_SHORT = 'exit short'¶
- MARKER_PROPERTIES = {'backtest end': {'color': 'green', 'size': 50, 'symbol': '*'}, 'enter long': {'color': 'blue', 'size': 50, 'symbol': 'P'}, 'enter short': {'color': 'red', 'size': 50, 'symbol': 'P'}, 'exit long': {'color': 'blue', 'size': 50, 'symbol': 'X'}, 'exit short': {'color': 'red', 'size': 50, 'symbol': 'X'}, 'none': {'color': 'green', 'size': 50, 'symbol': 'o'}, 'roll future': {'color': 'green', 'size': 50, 'symbol': '>'}}¶
- NONE = 'none'¶
- ROLL_FUTURE = 'roll future'¶
- class pyqstrat.pq_types.RollOrder(contract, timestamp, close_qty, reopen_qty, reason_code='roll future', properties=None, status='open')[source]¶
Bases:
Order
A roll order is used to roll a future from one series to the next. It represents a sell of one future and the buying of another future.
- __init__(contract, timestamp, close_qty, reopen_qty, reason_code='roll future', properties=None, status='open')[source]¶
- Parameters
contract (
Contract
) – The contract this order is fortimestamp (
datetime64
) – Time the order was placedclose_qty (
float
) – Quantity of the future you are rollingreopen_qty (
float
) – Quantity of the future you are rolling toreason_code (
str
) – The reason this order was created. Prefer a predefined constant from the ReasonCode class if it matches your reason for creating this order. Default Noneproperties (
Optional
[SimpleNamespace
]) – Any order specific data we want to store. Default Nonestatus (
str
) – Status of the order, “open”, “filled”, etc. (default “open”)
- class pyqstrat.pq_types.RoundTripTrade(contract, entry_order, exit_order, entry_timestamp, exit_timestamp, qty, entry_price, exit_price, entry_reason, exit_reason, entry_commission, exit_commission, entry_properties, exit_properties, net_pnl)[source]¶
Bases:
object
- entry_commission: float¶
- entry_price: float¶
- entry_properties: Optional[SimpleNamespace]¶
- entry_reason: str¶
- entry_timestamp: datetime64¶
- exit_commission: float¶
- exit_price: float¶
- exit_properties: Optional[SimpleNamespace]¶
- exit_reason: str¶
- exit_timestamp: datetime64¶
- net_pnl: float¶
- qty: int¶
- class pyqstrat.pq_types.StopLimitOrder(contract, timestamp, qty, trigger_price, limit_price=nan, reason_code='none', properties=None, status='open')[source]¶
Bases:
Order
Used for stop loss or stop limit orders. The order is triggered when price goes above or below trigger price, depending on whether this is a short or long order. Becomes either a market or limit order at that point, depending on whether you set the limit price or not.
- __init__(contract, timestamp, qty, trigger_price, limit_price=nan, reason_code='none', properties=None, status='open')[source]¶
- Parameters
contract (
Contract
) – The contract this order is fortimestamp (
datetime64
) – Time the order was placedqty (
float
) – Number of contracts or shares. Use a negative quantity for sell orderstrigger_price (
float
) – Order becomes a market or limit order if price crosses trigger_price.limit_price (
float
) – If not set (default), order becomes a market order when price crosses trigger price. Otherwise it becomes a limit order. Default np.nanreason_code (
str
) – The reason this order was created. Prefer a predefined constant from the ReasonCode class if it matches your reason for creating this order. Default Noneproperties (
Optional
[SimpleNamespace
]) – Any order specific data we want to store. Default Nonestatus (
str
) – Status of the order, “open”, “filled”, etc. (default “open”)
- class pyqstrat.pq_types.Trade(contract, order, timestamp, qty, price, fee=0.0, commission=0.0, properties=None)[source]¶
Bases:
object
- __init__(contract, order, timestamp, qty, price, fee=0.0, commission=0.0, properties=None)[source]¶
- Parameters
contract (
Contract
) – The contract we tradedorder (
Order
) – A reference to the order that created this trade. Default Nonetimestamp (
datetime64
) – Trade execution datetimeqty (
float
) – Number of contracts or shares filledprice (
float
) – Trade pricefee (
float
) – Fees paid to brokers or others. Default 0commision – Commission paid to brokers or others. Default 0
properties (
Optional
[SimpleNamespace
]) – Any data you want to store with this contract. For example, you may want to store bid / ask prices at time of trade. Default None
- pyqstrat.pq_io.df_to_hdf5(df, filename, key, dtypes=None, optimize_vlen_str=True)[source]¶
Write out a pandas dataframe to hdf5 using the np_arrays_to_hdf5 function
- Return type
None
- pyqstrat.pq_io.hdf5_to_df(filename, key)[source]¶
Read a pandas dataframe previously written out using df_to_hdf5 or np_arrays_to_hdf5
- Return type
DataFrame
- pyqstrat.pq_io.hdf5_to_np_arrays(filename, key)[source]¶
Read a list of numpy arrays previously written out by np_arrays_to_hdf5 :type filename:
str
:param filename: path of the hdf5 file to read :type key:str
:param key: group and or / subgroups to read from. For example, “g1/g2” will read from the subgrp g2 within the grp g1- Return type
List
[Tuple
[str
,ndarray
]]- Returns
a list of numpy arrays along with their names
- pyqstrat.pq_io.np_arrays_to_hdf5(data, filename, key, dtypes=None, optimize_vlen_str=True, compression_args=None)[source]¶
Write a list of numpy arrays to hdf5 :type data:
List
[Tuple
[str
,ndarray
]] :param data: List of numpy one dimensional arrays along with the name of the array :type filename:str
:param filename: filename of the hdf5 file :type key:str
:param key: group and or / subgroups to write to. For example, “g1/g2” will write to the subgrp g2 within the grp g1 :type dtypes:Optional
[Dict
[str
,str
]] :param dtypes: dict used to override datatype for a column. For example, {“col1”: “f4”} will write a 4 byte float array for col1 :type optimize_vlen_str:bool
:param optimize_vlen_str: if set, for every variable length string array, i.e dtype = ‘O’, we try to find the maximum string lengthand if it is < 100, we write out fixed length strings instead of variable length. This is much faster to read and process
- Parameters
compression_args (
Optional
[Dict
[Any
,Any
]]) – if you want to compress the hdf5 file. You can use the hdf5plugin module and arguments such as hdf5plugin.Blosc()- Return type
None
pyqstrat.holiday_calendars module¶
- class pyqstrat.holiday_calendars.Calendar(holidays)[source]¶
Bases:
object
- EUREX = 'eurex'¶
- NYSE = 'nyse'¶
- __init__(holidays)[source]¶
Do not use this function directly. Use Calendar.get_calendar instead :type holidays:
ndarray
:param holidays: holidays for this calendar, excluding weekends :type holidays: np.array of datetime64[D]
- static add_calendar(exchange_name, holidays)[source]¶
Add a trading calendar to the class level calendars dict
- Parameters
exchange_name (
str
) – Name of the exchange.holidays (
ndarray
) – holidays for this exchange, excluding weekends
- Return type
None
- add_trading_days(start, num_days, roll='raise')[source]¶
Adds trading days to a start date
- Parameters
start (
Union
[datetime64
,Series
,ndarray
,str
,datetime
,date
]) – start datetimes(s)num_days (
Union
[int
,ndarray
]) – number of trading days to addroll (
str
) – one of ‘raise’, ‘nat’, ‘forward’, ‘following’, ‘backward’, ‘preceding’, ‘modifiedfollowing’, ‘modifiedpreceding’ or ‘allow’} ‘allow’ is a special case in which case, adding 1 day to a holiday will act as if it was not a holiday, and give you the next business day’ The rest of the values are the same as in the numpy busday_offset function From numpy documentation: How to treat dates that do not fall on a valid day. The default is ‘raise’. ‘raise’ means to raise an exception for an invalid day. ‘nat’ means to return a NaT (not-a-time) for an invalid day. ‘forward’ and ‘following’ mean to take the first valid day later in time. ‘backward’ and ‘preceding’ mean to take the first valid day earlier in time. ‘modifiedfollowing’ means to take the first valid day later in time unless it is across a Month boundary, in which case to take the first valid day earlier in time. ‘modifiedpreceding’ means to take the first valid day earlier in time unless it is across a Month boundary, in which case to take the first valid day later in time.
- Return type
Union
[datetime64
,ndarray
]- Returns
The datetime num_days trading days after start
>>> calendar = Calendar.get_calendar(Calendar.NYSE) >>> calendar.add_trading_days(datetime.date(2015, 12, 24), 1) numpy.datetime64('2015-12-28') >>> calendar.add_trading_days(np.datetime64('2017-04-15'), 0, roll = 'preceding') # 4/14/2017 is a Friday and a holiday numpy.datetime64('2017-04-13') >>> calendar.add_trading_days(np.datetime64('2017-04-08'), 0, roll = 'preceding') # 4/7/2017 is a Friday and not a holiday numpy.datetime64('2017-04-07') >>> calendar.add_trading_days(np.datetime64('2019-02-17 15:25'), 1, roll = 'allow') numpy.datetime64('2019-02-19T15:25') >>> calendar.add_trading_days(np.datetime64('2019-02-17 15:25'), -1, roll = 'allow') numpy.datetime64('2019-02-15T15:25')
- static get_calendar(exchange_name)[source]¶
Get a calendar object for the given exchange:
- Parameters
exchange_name (
str
) – The exchange for which you want a calendar. Calendar.NYSE, Calendar.EUREX are predefined.calendar (If you want to add a new) –
function (use the add_calendar class level) –
- Return type
- Returns
The calendar object
- get_trading_days(start, end, include_first=False, include_last=True)[source]¶
Get back a list of numpy dates that are trading days between the start and end
>>> nyse = Calendar.get_calendar(Calendar.NYSE) >>> nyse.get_trading_days('2005-01-01', '2005-01-08') array(['2005-01-03', '2005-01-04', '2005-01-05', '2005-01-06', '2005-01-07'], dtype='datetime64[D]') >>> nyse.get_trading_days(datetime.date(2005, 1, 1), datetime.date(2005, 2, 1)) array(['2005-01-03', '2005-01-04', '2005-01-05', '2005-01-06', '2005-01-07', '2005-01-10', '2005-01-11', '2005-01-12', '2005-01-13', '2005-01-14', '2005-01-18', '2005-01-19', '2005-01-20', '2005-01-21', '2005-01-24', '2005-01-25', '2005-01-26', '2005-01-27', '2005-01-28', '2005-01-31', '2005-02-01'], dtype='datetime64[D]') >>> nyse.get_trading_days(datetime.date(2016, 1, 5), datetime.date(2016, 1, 29), include_last = False) array(['2016-01-06', '2016-01-07', '2016-01-08', '2016-01-11', '2016-01-12', '2016-01-13', '2016-01-14', '2016-01-15', '2016-01-19', '2016-01-20', '2016-01-21', '2016-01-22', '2016-01-25', '2016-01-26', '2016-01-27', '2016-01-28'], dtype='datetime64[D]') >>> nyse.get_trading_days('2017-07-04', '2017-07-08', include_first = False) array(['2017-07-05', '2017-07-06', '2017-07-07'], dtype='datetime64[D]') >>> nyse.get_trading_days(np.datetime64('2017-07-04'), np.datetime64('2017-07-08'), include_first = False) array(['2017-07-05', '2017-07-06', '2017-07-07'], dtype='datetime64[D]')
- Return type
Union
[int
,ndarray
]
- is_trading_day(dates)[source]¶
Returns whether the date is not a holiday or a weekend
- Parameters
dates (
Union
[datetime64
,Series
,ndarray
,str
,datetime
,date
]) – date times to check- Return type
Union
[bool
,ndarray
]- Returns
Whether this date is a trading day
>>> import datetime >>> eurex = Calendar.get_calendar(Calendar.EUREX) >>> eurex.is_trading_day('2016-12-25') False >>> eurex.is_trading_day(datetime.date(2016, 12, 22)) True >>> nyse = Calendar.get_calendar(Calendar.NYSE) >>> nyse.is_trading_day('2017-04-01') # Weekend False >>> nyse.is_trading_day(np.arange('2017-04-01', '2017-04-09', dtype = np.datetime64)) array([False, False, True, True, True, True, True, False]...)
- num_trading_days(start, end, include_first=False, include_last=True)[source]¶
Count the number of trading days between two date series including those two dates
>>> eurex = Calendar.get_calendar(Calendar.EUREX) >>> eurex.num_trading_days('2009-01-01', '2011-12-31') 772.0 >>> dates = pd.date_range('20130101',periods=8) >>> increments = np.array([5, 0, 3, 9, 4, 10, 15, 29]) >>> import warnings >>> import pandas as pd >>> warnings.filterwarnings(action = 'ignore', category = pd.errors.PerformanceWarning) >>> dates2 = dates + increments * dates.freq >>> df = pd.DataFrame({'x': dates, 'y' : dates2}) >>> df.iloc[4]['x'] = np.nan >>> df.iloc[6]['y'] = np.nan >>> nyse = Calendar.get_calendar(Calendar.NYSE) >>> np.set_printoptions(formatter = {'float' : lambda x : f'{x:.1f}'}) # After numpy 1.13 positive floats don't have a leading space for sign >>> print(nyse.num_trading_days(df.x, df.y)) [3.0 0.0 1.0 5.0 nan 8.0 nan 20.0]
- Return type
Union
[float
,ndarray
]
pyqstrat.account module¶
- class pyqstrat.account.Account(contract_groups, timestamps, price_function, strategy_context, starting_equity=1000000.0, pnl_calc_time=900)[source]¶
Bases:
object
An Account calculates pnl for a set of contracts
- __init__(contract_groups, timestamps, price_function, strategy_context, starting_equity=1000000.0, pnl_calc_time=900)[source]¶
- Parameters
contract_groups (
Sequence
[ContractGroup
]) – Contract groups that we want to compute PNL fortimestamps (
ndarray
) – Timestamps that we might compute PNL atprice_function (
Callable
[[Contract
,ndarray
,int
,SimpleNamespace
],float
]) – Function that returns contract prices used to compute pnlstrategy_context (
SimpleNamespace
) – This is passed into the price function so we can use current state of strategy to compute pricesstarting_equity (
float
) – Starting equity in account currency. Default 1.e6pnl_calc_time (
int
) – Number of minutes past midnight that we should calculate PNL at. Default 15 * 60, i.e. 3 pm
- calc(timestamp)[source]¶
Computes P&L and stores it internally for all contracts.
- Parameters
timestamp (
datetime64
) – timestamp to compute P&L at. Account remembers the last timestamp it computed P&L up to and will compute P&L between these and including timestamp. If there is more than one day between the last index and current index, we will include pnl for at the defined pnl_calc_time for those dates as well.- Return type
None
- df_account_pnl(contract_group=None)[source]¶
Returns PNL at the account level.
- Parameters
contract_group (
Optional
[ContractGroup
]) – If set, we only return pnl for this contract_group. Otherwise we return pnl for all contract groups- Return type
DataFrame
- df_pnl(contract_groups=None)[source]¶
Returns a dataframe with P&L columns broken down by contract group and symbol
- Parameters
contract_group – Return PNL for this contract group. If None (default), include all contract groups
- Return type
DataFrame
- df_roundtrip_trades(contract_group=None, start_date=None, end_date=None)[source]¶
Returns a dataframe of round trip trades
- Parameters
contract_group (
Optional
[ContractGroup
]) – Return trades for this contract group. If None (default), include all contract groupsstart_date (
Optional
[datetime64
]) – Include trades with date greater than or equal to this timestamp.end_date (
Optional
[datetime64
]) – Include trades with date less than or equal to this timestamp.
- Return type
DataFrame
- df_trades(contract_group=None, start_date=None, end_date=None)[source]¶
Returns a dataframe of trades
- Parameters
contract_group (
Optional
[ContractGroup
]) – Return trades for this contract group. If None (default), include all contract groupsstart_date (
Optional
[datetime64
]) – Include trades with date greater than or equal to this timestamp.end_date (
Optional
[datetime64
]) – Include trades with date less than or equal to this timestamp.
- Return type
DataFrame
- equity(timestamp)[source]¶
Returns equity in this account in Account currency. Will cause calculation if Account has not previously calculated up to this date
- Return type
float
- position(contract_group, timestamp)[source]¶
Returns netted position for a contract_group at a given date in number of contracts or shares.
- Return type
float
- positions(contract_group, timestamp)[source]¶
Returns all non-zero positions in a contract group
- Return type
MutableSequence
[Tuple
[Contract
,float
]]
- roundtrip_trades(contract_group=None, start_date=None, end_date=None)[source]¶
Returns a list of round trip trades with the given symbol and with trade date between (and including) start date and end date if they are specified. If symbol is None trades for all symbols are returned
- Return type
MutableSequence
[RoundTripTrade
]
- class pyqstrat.account.ContractPNL(contract, account_timestamps, price_function, strategy_context)[source]¶
Bases:
object
Computes pnl for a single contract over time given trades and market data >>> from pyqstrat.pq_types import MarketOrder >>> ContractGroup.clear() >>> Contract.clear() >>> aapl_cg = ContractGroup.create(‘AAPL’) >>> aapl_contract = Contract.create(‘AAPL’, contract_group=aapl_cg) >>> timestamps = np.arange(np.datetime64(‘2018-01-01’), np.datetime64(‘2018-01-04’)) >>> def get_price(contract, timestamps, idx, strategy_context): … assert contract.symbol == ‘AAPL’, f’unknown contract: {contract}’ … return idx + 10.1
>>> contract_pnl = ContractPNL(aapl_contract, timestamps, get_price, SimpleNamespace()) >>> trade_5 = Trade(aapl_contract, MarketOrder(aapl_contract, timestamps[1], 20), timestamps[2], 10, 16.2) >>> trade_6 = Trade(aapl_contract, MarketOrder(aapl_contract, timestamps[1], -20), timestamps[2], -10, 16.5) >>> trade_7 = Trade(aapl_contract, MarketOrder(aapl_contract, timestamps[1], -20), timestamps[2], -10, 16.5) >>> contract_pnl._add_trades([trade_5, trade_6]) >>> contract_pnl._add_trades([trade_7]) >>> df = contract_pnl.df() >>> assert (len(df == 1)) >>> row = df.iloc[0] >>> assert row.to_dict() == {'symbol': 'AAPL', ... 'timestamp': pd.Timestamp('2018-01-03 00:00:00'), ... 'position': -10, ... 'price': 12.1, ... 'unrealized': 44.0, ... 'realized': 3.000000000000007, ... 'commission': 0.0, ... 'fee': 0.0, ... 'net_pnl': 47.00000000000001}
- pyqstrat.account.calc_trade_pnl(open_qtys, open_prices, new_qtys, new_prices, multiplier)[source]¶
>>> print(calc_trade_pnl( ... open_qtys = np.array([], dtype = float), open_prices = np.array([], dtype = float), ... new_qtys = np.array([-8, 9, -4]), new_prices = np.array([10, 11, 6]), multiplier = 100)) (array([-3.]), array([6.]), -3.0, 6.0, -1300.0) >>> print(calc_trade_pnl(open_qtys = np.array([], dtype = float), open_prices = np.array([], dtype = float), new_qtys = np.array([3, 10, -5]), ... new_prices = np.array([51, 50, 45]), multiplier = 100)) (array([8.]), array([50.]), 8.0, 50.0, -2800.0) >>> print(calc_trade_pnl(open_qtys = np.array([]), open_prices = np.array([]), ... new_qtys = np.array([-58, -5, -5, 6, -8, 5, 5, -5, 19, 7, 5, -5, 39]), ... new_prices = np.array([2080, 2075.25, 2070.75, 2076, 2066.75, 2069.25, 2074.75, 2069.75, 2087.25, 2097.25, 2106, 2088.25, 2085.25]), ... multiplier = 50)) (array([], dtype=float64), array([], dtype=float64), 0.0, 0, -33762.5)
- Return type
Tuple
[ndarray
,ndarray
,float
,float
,float
]
pyqstrat.strategy module¶
- class pyqstrat.strategy.Strategy(timestamps, contract_groups, price_function, starting_equity=1000000.0, pnl_calc_time=901, trade_lag=0, run_final_calc=True, strategy_context=None)[source]¶
Bases:
object
- __init__(timestamps, contract_groups, price_function, starting_equity=1000000.0, pnl_calc_time=901, trade_lag=0, run_final_calc=True, strategy_context=None)[source]¶
- Parameters
timestamps (np.array of np.datetime64) – The “heartbeat” of the strategy. We will evaluate trading rules and simulate the market at these times.
contract_groups (
Sequence
[ContractGroup
]) – The contract groups we will potentially trade.price_function (
Callable
[[Contract
,ndarray
,int
,SimpleNamespace
],float
]) – A function that returns the price of a contract at a given timestampstarting_equity (
float
) – Starting equity in Strategy currency. Default 1.e6pnl_calc_time (
int
) – Time of day used to calculate PNL. Default 15 * 60 (3 pm)trade_lag (
int
) – Number of bars you want between the order and the trade. For example, if you think it will take 5 seconds to place your order in the market, and your bar size is 1 second, set this to 5. Set this to 0 if you want to execute your trade at the same time as you place the order, for example, if you have daily bars. Default 0.run_final_calc (
bool
) – If set, calculates unrealized pnl and net pnl as well as realized pnl when strategy is done. If you don’t need unrealized pnl, turn this off for faster run time. Default Truestrategy_context (
Optional
[SimpleNamespace
]) – A storage class where you can store key / value pairs relevant to this strategy. For example, you may have a pre-computed table of correlations that you use in the indicator or trade rule functions. If not set, the __init__ function will create an empty member strategy_context object that you can access.
- add_indicator(name, indicator, contract_groups=None, depends_on=None)[source]¶
- Parameters
name (
str
) – Name of the indicatorindicator (
Union
[ndarray
,Series
,Callable
[[ContractGroup
,ndarray
,SimpleNamespace
,SimpleNamespace
],ndarray
]]) – A function that takes strategy timestamps and other indicators and returns a numpy array containing indicator values. The return array must have the same length as the timestamps object. Can also be a numpy array or a pandas Series in which case we just store the values.contract_groups (
Optional
[Sequence
[ContractGroup
]]) – Contract groups that this indicator applies to. If not set, it applies to all contract groups. Default None.depends_on (
Optional
[Sequence
[str
]]) – Names of other indicators that we need to compute this indicator. Default None.
- Return type
None
- add_market_sim(market_sim_function)[source]¶
Add a market simulator. A market simulator is a function that takes orders as input and returns trades.
- Return type
None
- add_rule(name, rule_function, signal_name, sig_true_values=None, position_filter=None)[source]¶
- Add a trading rule. Trading rules are guaranteed to run in the order in which you add them. For example, if you set trade_lag to 0,
and want to exit positions and re-enter new ones in the same bar, make sure you add the exit rule before you add the entry rule to the strategy.
- Parameters
name (
str
) – Name of the trading rulerule_function (
Callable
[[ContractGroup
,int
,ndarray
,SimpleNamespace
,ndarray
,Account
,SimpleNamespace
],Sequence
[Order
]]) – A trading rule function that returns a list of Orderssignal_name (
str
) – The strategy will call the trading rule function when the signal with this name matches sig_true_valuessig_true_values (
Optional
[Sequence
]) – If the signal value at a bar is equal to one of these values, the Strategy will call the trading rule function. Default [TRUE]position_filter (
Optional
[str
]) – Can be “zero”, “nonzero” or None. Zero rules are only triggered when the corresponding contract positions are 0 Nonzero rules are only triggered when the corresponding contract positions are non-zero. If not set, we don’t look at position before triggering the rule. Default None
- Return type
None
- add_signal(name, signal_function, contract_groups=None, depends_on_indicators=None, depends_on_signals=None)[source]¶
- Parameters
name (str) – Name of the signal
signal_function (function) – A function that takes timestamps and a dictionary of indicator value arrays and returns a numpy array containing signal values. The return array must have the same length as the input timestamps
contract_groups (list of
ContractGroup
, optional) – Contract groups that this signal applies to. If not set, it applies to all contract groups. Default None.depends_on_indicators (list of str, optional) – Names of indicators that we need to compute this signal. Default None.
depends_on_signals (list of str, optional) – Names of other signals that we need to compute this signal. Default None.
- Return type
None
- df_data(contract_groups=None, add_pnl=True, start_date=None, end_date=None)[source]¶
Add indicators and signals to end of market data and return as a pandas dataframe.
- Parameters
contract_groups (list of:obj:ContractGroup, optional) – list of contract groups to include. All if set to None (default)
add_pnl (
bool
) – If True (default), include P&L columns in dataframestart_date (
Union
[str
,datetime64
,None
]) – string or numpy datetime64. Default Noneend_date (
Union
[str
,datetime64
,None
]) – string or numpy datetime64: Default None
- Return type
DataFrame
- df_orders(contract_group=None, start_date=None, end_date=None)[source]¶
Returns a dataframe with data from orders with the given contract group and with order date between (and including) start date and end date if they are specified. If contract_group is None orders for all contract_groups are returned
- Return type
DataFrame
- df_pnl(contract_group=None)[source]¶
Returns a dataframe with P&L columns. If contract group is set to None (default), sums up P&L across all contract groups
- Return type
DataFrame
- df_returns(contract_group=None, sampling_frequency='D')[source]¶
Return a dataframe of returns and equity indexed by date.
- Parameters
contract_group (
Optional
[ContractGroup
]) – The contract group to get returns for. If set to None (default), we return the sum of PNL for all contract groupssampling_frequency (
str
) – Downsampling frequency. Default is None. See pandas frequency strings for possible values
- Return type
DataFrame
- df_roundtrip_trades(contract_group=None, start_date=None, end_date=None)[source]¶
Returns a dataframe of round trip trades with the given contract group and with trade date between (and including) start date and end date if they are specified. If contract_group is None trades for all contract_groups are returned
- Return type
DataFrame
- df_trades(contract_group=None, start_date=None, end_date=None)[source]¶
Returns a dataframe with data from trades with the given contract group and with trade date between (and including) start date and end date if they are specified. If contract_group is None trades for all contract_groups are returned
- Return type
DataFrame
- evaluate_returns(contract_group=None, plot=True, display_summary=True, float_precision=4, return_metrics=False)[source]¶
Returns a dictionary of common return metrics.
- Parameters
contract_group (
ContractGroup
, optional) – Contract group to evaluate or None (default) for all contract groupsplot (bool) – If set to True, display plots of equity, drawdowns and returns. Default False
float_precision (float, optional) – Number of significant figures to show in returns. Default 4
return_metrics (bool, optional) – If set, we return the computed metrics as a dictionary
- Return type
Optional
[Mapping
]
- orders(contract_group=None, start_date=None, end_date=None)[source]¶
Returns a list of orders with the given contract group and with order date between (and including) start date and end date if they are specified. If contract_group is None orders for all contract_groups are returned
- Return type
Sequence
[Order
]
- plot(contract_groups=None, primary_indicators=None, primary_indicators_dual_axis=None, secondary_indicators=None, secondary_indicators_dual_axis=None, indicator_properties=None, signals=None, signal_properties=None, pnl_columns=None, title=None, figsize=(20, 15), _date_range=None, date_format=None, sampling_frequency=None, trade_marker_properties=None, hspace=0.15)[source]¶
Plot indicators, signals, trades, position, pnl
- Parameters
contract_groups (
Optional
[Sequence
[ContractGroup
]]) – Contract groups to plot or None (default) for all contract groups.indicators (primary) – List of indicators to plot in the main indicator section. Default None (plot everything)
indicators – List of indicators to plot in the secondary indicator section. Default None (don’t plot anything)
indicator_properties (
Optional
[Mapping
[str
,Mapping
[str
,Any
]]]) – If set, we use the line color, line type indicated for the given indicatorssignals (
Optional
[Sequence
[str
]]) – Signals to plot. Default None (plot everything).plot_equity – If set, we plot the equity curve. Default is True
title (
Optional
[str
]) – Title of plot. Default Nonefigsize (
Tuple
[int
,int
]) – Figure size. Default (20, 15)date_range – Used to restrict the date range of the graph. Default None
date_format (
Optional
[str
]) – Date format for tick labels on x axis. If set to None (default), will be selected based on date range. See matplotlib date format stringssampling_frequency (
Optional
[str
]) – Downsampling frequency. The graph may get too busy if you have too many bars of data, so you may want to downsample before plotting. See pandas frequency strings for possible values. Default None.trade_marker_properties (
Optional
[Mapping
[str
,Mapping
[str
,Any
]]]) – A dictionary of order reason code -> marker shape, marker size, marker color for plotting trades with different reason codes. By default we use the dictionary from theReasonCode
classhspace (
float
) – Height (vertical) space between subplots. Default is 0.15
- Return type
None
- plot_returns(contract_group=None)[source]¶
Display plots of equity, drawdowns and returns for the given contract group or for all contract groups if contract_group is None (default)
- Return type
Optional
[Tuple
[Figure
,Axes
]]
- roundtrip_trades(contract_group=None, start_date=None, end_date=None)[source]¶
Returns a list of trades with the given contract group and with trade date between (and including) start date and end date if they are specified. If contract_group is None trades for all contract_groups are returned
- Return type
Sequence
[RoundTripTrade
]
- run_indicators(indicator_names=None, contract_groups=None, clear_all=False)[source]¶
Calculate values of the indicators specified and store them.
- Parameters
indicator_names (
Optional
[Sequence
[str
]]) – List of indicator names. If None (default) run all indicatorscontract_groups (
Optional
[Sequence
[ContractGroup
]]) – Contract group to run this indicator for. If None (default), we run it for all contract groups.clear_all (
bool
) – If set, clears all indicator values before running. Default False.
- Return type
None
- run_rules(rule_names=None, contract_groups=None, start_date=None, end_date=None)[source]¶
Run trading rules.
- Parameters
rule_names (
Optional
[Sequence
[str
]]) – List of rule names. If None (default) run all rulescontract_groups (
Optional
[Sequence
[ContractGroup
]]) – Contract groups to run this rule for. If None (default), we run it for all contract groups.start_date (
Optional
[datetime64
]) – Run rules starting from this date. Default Noneend_date (
Optional
[datetime64
]) – Don’t run rules after this date. Default None
- Return type
None
- run_signals(signal_names=None, contract_groups=None, clear_all=False)[source]¶
Calculate values of the signals specified and store them.
- Parameters
signal_names (
Optional
[Sequence
[str
]]) – List of signal names. If None (default) run all signalscontract_groups (
Optional
[Sequence
[ContractGroup
]]) – Contract groups to run this signal for. If None (default), we run it for all contract groups.clear_all (
bool
) – If set, clears all signal values before running. Default False.
- Return type
None
- trades(contract_group=None, start_date=None, end_date=None)[source]¶
Returns a list of trades with the given contract group and with trade date between (and including) start date and end date if they are specified. If contract_group is None trades for all contract_groups are returned
- Return type
Sequence
[Trade
]
pyqstrat.portfolio module¶
- class pyqstrat.portfolio.Portfolio(name='main')[source]¶
Bases:
object
A portfolio contains one or more strategies that run concurrently so you can test running strategies that are uncorrelated together.
- add_strategy(name, strategy)[source]¶
- Parameters
name (
str
) – Name of the strategystrategy (
Strategy
) – Strategy instance
- Return type
None
- df_returns(sampling_frequency='D', strategy_names=None)[source]¶
Return dataframe containing equity and returns with a date index. Equity and returns are combined from all strategies passed in.
- Parameters
sampling_frequency (
str
) – Date frequency for rows. Default ‘D’ for daily so we will have one row per daystrategy_names (
Optional
[Sequence
[str
]]) – By default this is set to None and we use all strategies.
- Return type
DataFrame
- evaluate_returns(sampling_frequency='D', strategy_names=None, plot=True, float_precision=4)[source]¶
Returns a dictionary of common return metrics.
- Parameters
sampling_frequency (
str
) – Date frequency. Default ‘D’ for daily so we downsample to daily returns before computing metricsstrategy_names (
Optional
[Sequence
[str
]]) – By default this is set to None and we use all strategies.plot (
bool
) – If set to True, display plots of equity, drawdowns and returns. Default Falsefloat_precision (
int
) – Number of significant figures to show in returns. Default 4
- Return type
Mapping
- plot(sampling_frequency='D', strategy_names=None)[source]¶
Display plots of equity, drawdowns and returns
- Parameters
sampling_frequency (
str
) – Date frequency. Default ‘D’ for daily so we downsample to daily returns before computing metricsstrategy_names (
Optional
[Sequence
[str
]]) – A list of strategy names. By default this is set to None and we use all strategies.
- Return type
None
- run(strategy_names=None, start_date=None, end_date=None)[source]¶
Run indicators, signals and rules.
- Parameters
strategy_names (
Optional
[Sequence
[str
]]) – A list of strategy names. By default this is set to None and we use all strategies.start_date (
Optional
[datetime64
]) – Run rules starting from this date. Sometimes we have a few strategies in a portfolio that need different lead times before they are ready to trade so you can set this so they are all ready by this date. Default Noneend_date (
Optional
[datetime64
]) – Don’t run rules after this date. Default None
- Return type
None
- run_indicators(strategy_names=None)[source]¶
Compute indicators for the strategies specified
- Parameters
strategy_names (
Optional
[Sequence
[str
]]) – By default this is set to None and we use all strategies.- Return type
None
pyqstrat.optimize module¶
- class pyqstrat.optimize.Experiment(suggestion, cost, other_costs)[source]¶
Bases:
object
An Experiment stores a suggestion and its result
- __init__(suggestion, cost, other_costs)[source]¶
- Parameters
suggestion (
Mapping
[str
,Any
]) – A dictionary of variable name -> valuecost (
float
) – A float representing output of the function we are testing with this suggestion as input.other_costs (
Mapping
[str
,float
]) – A dictionary of other results we want to store and look at later.
- class pyqstrat.optimize.Optimizer(name, generator, cost_func, max_processes=None)[source]¶
Bases:
object
Optimizer is used to optimize parameters for a strategy.
- __init__(name, generator, cost_func, max_processes=None)[source]¶
- Parameters
name (
str
) – Display title for plotting, etc.generator (
Generator
[Mapping
[str
,Any
],Tuple
[float
,Mapping
[str
,float
]],None
]) – A generator (see Python Generators) that takes no inputs and yields a dictionary with parameter name -> parameter value.cost_func (
Callable
[[Mapping
[str
,Any
]],Tuple
[float
,Mapping
[str
,float
]]]) – A function that takes a dictionary of parameter name -> parameter value as input and outputs cost for that set of parameters.max_processes (
Optional
[int
]) – If not set, the Optimizer will look at the number of CPU cores on your machine to figure out how many processes to run.
- df_experiments(sort_column='cost', ascending=True)[source]¶
Returns a dataframe containing experiment data, sorted by sort_column (default “cost”)
- Return type
DataFrame
- experiment_list(sort_order='lowest_cost')[source]¶
Returns the list of experiments we have run
- Parameters
sort_order (
str
) – Can be set to lowest_cost, highest_cost or sequence. If set to sequence, experiments are returned in the sequence in which they were run- Return type
Sequence
[Experiment
]
- plot_2d(x, y='all', plot_type='line', figsize=(15, 8), marker='X', marker_size=50, marker_color='r', xlim=None, hspace=None)[source]¶
Creates a 2D plot of the optimization output for plotting 1 parameter and costs
- Parameters
x (
str
) – Name of the parameter to plot on the x axis, corresponding to the same name in the generator.y (
str
) – Can be one of: “cost” The name of another cost variable corresponding to the output from the cost function “all”, which creates a subplot for cost plus all other costsplot_type (
str
) – line or scatter (default line)figsize (
Tuple
[float
,float
]) – Figure sizemarker (
str
) – Adds a marker to each point in x, y to show the actual data used for interpolation. You can set this to None to turn markers off.hspace (
Optional
[float
]) – Vertical space between subplots
- Return type
None
- plot_3d(x, y, z='all', filter_func=None, plot_type='surface', figsize=(15, 15), interpolation='linear', cmap='viridis', marker='X', marker_size=50, marker_color='r', xlim=None, ylim=None, hspace=None)[source]¶
Creates a 3D plot of the optimization output for plotting 2 parameters and costs.
- Parameters
x (
str
) – Name of the parameter to plot on the x axis, corresponding to the same name in the generator.y (
str
) – Name of the parameter to plot on the y axis, corresponding to the same name in the generator.z (
str
) – Can be one of: “cost” The name of another cost variable corresponding to the output from the cost function “all”, which creates a subplot for cost plus all other costsfilter_func (
Optional
[Callable
[[DataFrame
],DataFrame
]]) – A function that can be used to reduce the dataset before plotting. For example, you may want to filter on a dimension beyond x, y, z to pick a single value from that dimensionplot_type (
str
) – surface or contour (default surface)figsize (
Tuple
[float
,float
]) – Figure sizeinterpolation (
str
) – Can be ‘linear’, ‘nearest’ or ‘cubic’ for plotting z points between the ones passed in. See scipy.interpolate.griddata for detailscmap (
str
) – Colormap to use (default viridis). See matplotlib colormap for detailsmarker (
str
) – Adds a marker to each point in x, y, z to show the actual data used for interpolation. You can set this to None to turn markers off.hspace (
Optional
[float
]) – Vertical space between subplots
- Return type
None
pyqstrat.plot module¶
- class pyqstrat.plot.BarPlotAttributes(color='red')[source]¶
Bases:
DisplayAttributes
- color: str = 'red'¶
- class pyqstrat.plot.BoxPlotAttributes(proportional_widths=True, show_means=True, show_all=True, show_outliers=False, notched=False)[source]¶
Bases:
DisplayAttributes
- proportional_widths¶
if set to True, the width each box in the boxplot will be proportional to the number of items in its corresponding array
- Type
bool
- show_means¶
Whether to display a marker where the mean is for each array
- Type
bool
- show_outliers¶
Whether to show markers for outliers that are outside the whiskers. Box is at Q1 = 25%, Q3 = 75% quantiles, whiskers are at Q1 - 1.5 * (Q3 - Q1), Q3 + 1.5 * (Q3 - Q1)
- Type
bool
- notched¶
Whether to show notches indicating the confidence interval around the median
- Type
bool
- notched: bool = False¶
- proportional_widths: bool = True¶
- show_all: bool = True¶
- show_means: bool = True¶
- show_outliers: bool = False¶
- class pyqstrat.plot.BucketedValues(name, bucket_names, bucket_values, display_attributes=None)[source]¶
Bases:
PlotData
- Data in a subplot where we summarize properties of a numpy array.
For example, drawing a boxplot with percentiles. x axis is a categorical
- __init__(name, bucket_names, bucket_values, display_attributes=None)[source]¶
- Parameters
name (
str
) – name used for this data in a plot legendbucket_names (
Sequence
[str
]) – list of strings used on x axis labelsbucket_values (
Sequence
[ndarray
]) – list of numpy arrays that are summarized in this plot
- display_attributes: DisplayAttributes¶
- name: str¶
- class pyqstrat.plot.CandleStickPlotAttributes(colorup='darkgreen', colordown='#F2583E')[source]¶
Bases:
DisplayAttributes
- colordown: str = '#F2583E'¶
- colorup: str = 'darkgreen'¶
- class pyqstrat.plot.ContourPlotAttributes(marker='X', marker_size=50, marker_color='red', interpolation='linear', cmap=<matplotlib.colors.LinearSegmentedColormap object>, min_level=nan, max_level=nan)[source]¶
Bases:
DisplayAttributes
- cmap: Colormap = <matplotlib.colors.LinearSegmentedColormap object>¶
- interpolation: str = 'linear'¶
- marker: str = 'X'¶
- marker_color: str = 'red'¶
- marker_size: int = 50¶
- max_level: float = nan¶
- min_level: float = nan¶
- class pyqstrat.plot.DateFormatter(timestamps, fmt)[source]¶
Bases:
Formatter
Formats timestamps on plot axes. See matplotlib Formatter
- class pyqstrat.plot.DateLine(date, name=None, line_type='dashed', color=None)[source]¶
Bases:
object
Draw a vertical line on a plot with a datetime x-axis
- class pyqstrat.plot.FilledLinePlotAttributes(positive_color='blue', negative_color='red')[source]¶
Bases:
DisplayAttributes
colorup: Color for bars where close >= open. Default “darkgreen” colordown: Color for bars where open < close. Default “#F2583E”
- negative_color: str = 'red'¶
- positive_color: str = 'blue'¶
- class pyqstrat.plot.HorizontalLine(y, name=None, line_type='dashed', color=None)[source]¶
Bases:
object
Draws a horizontal line on a subplot
- class pyqstrat.plot.LinePlotAttributes(line_type='solid', line_width=None, color=None, marker=None, marker_size=None, marker_color=None)[source]¶
Bases:
DisplayAttributes
- color: Optional[str] = None¶
- line_type: Optional[str] = 'solid'¶
- line_width: Optional[int] = None¶
- marker: Optional[str] = None¶
- marker_color: Optional[str] = None¶
- marker_size: Optional[int] = None¶
- class pyqstrat.plot.Plot(subplot_list, title=None, figsize=(15, 8), date_range=None, date_format=None, sampling_frequency=None, show_grid=True, show_date_gaps=True, hspace=0.15)[source]¶
Bases:
object
Top level plot containing a list of subplots to draw
- __init__(subplot_list, title=None, figsize=(15, 8), date_range=None, date_format=None, sampling_frequency=None, show_grid=True, show_date_gaps=True, hspace=0.15)[source]¶
- Parameters
subplot_list (
Sequence
[Subplot
]) – List of Subplot objects to drawtitle (
Optional
[str
]) – Title for this plot. Default Nonefigsize (
Tuple
[float
,float
]) – Figure size. Default (15, 8)date_range (
Union
[Tuple
[str
,str
],Tuple
[Optional
[datetime64
],Optional
[datetime64
]],None
]) – Tuple of strings or numpy datetime64 limiting timestamps to draw. e.g. (“2018-01-01 14:00”, “2018-01-05”). Default Nonedate_format (
Optional
[str
]) – Date format to use for x-axissampling_frequency (
Optional
[str
]) – Set this to downsample subplots that have a datetime x axis. For example, if you have minute bar data, you might want to subsample to hours if the plot is too crowded. See pandas time frequency strings for possible values. Default Noneshow_grid (
bool
) – If set to True, show a grid on the subplots. Default Trueshow_date_gaps (
bool
) – If set to True, then when there is a gap between timestamps will draw a dashed vertical line. For example, you may have minute bars and a gap between end of trading day and beginning of next day. Even if set to True, this will turn itself off if there are too many gaps to avoid clutter. Default Truehspace (
Optional
[float
]) – Height (vertical) space between subplots. Default 0.15
- class pyqstrat.plot.PlotData[source]¶
Bases:
object
- display_attributes: DisplayAttributes¶
- name: str¶
- class pyqstrat.plot.ScatterPlotAttributes(marker='X', marker_size=50, marker_color='red')[source]¶
Bases:
DisplayAttributes
- marker: str = 'X'¶
- marker_color: str = 'red'¶
- marker_size: int = 50¶
- class pyqstrat.plot.Subplot(data_list, secondary_y=None, title=None, xlabel=None, ylabel=None, zlabel=None, date_lines=None, horizontal_lines=None, vertical_lines=None, xlim=None, ylim=None, height_ratio=1.0, display_legend=True, legend_loc='best', log_y=False, y_tick_format=None)[source]¶
Bases:
object
A top level plot contains a list of subplots, each of which contain a list of data objects to draw
- __init__(data_list, secondary_y=None, title=None, xlabel=None, ylabel=None, zlabel=None, date_lines=None, horizontal_lines=None, vertical_lines=None, xlim=None, ylim=None, height_ratio=1.0, display_legend=True, legend_loc='best', log_y=False, y_tick_format=None)[source]¶
- Parameters
data_list (
Union
[PlotData
,Sequence
[PlotData
]]) – A list of objects to draw. Each element can contain XYData, XYZData, TimeSeries, TradeBarSeries, BucketedValues or TradeSetsecondary_y (
Optional
[Sequence
[str
]]) – A list of objects to draw on the secondary y axistitle (
Optional
[str
]) – Title to show for this subplot. Default Nonezlabel (
Optional
[str
]) – Only applicable to 3d subplots. Default Nonedate_lines (
Optional
[Sequence
[DateLine
]]) – A list of DateLine objects to draw as vertical lines. Only applicable when x axis is datetime. Default Nonehorizontal_lines (
Optional
[Sequence
[HorizontalLine
]]) – A list of HorizontalLine objects to draw on the plot. Default Nonevertical_lines (
Optional
[Sequence
[VerticalLine
]]) – A list of VerticalLine objects to draw on the plotxlim (
Union
[Tuple
[float
,float
],Tuple
[datetime64
,datetime64
],None
]) – x limits for the plot as a tuple of numpy datetime objects when x-axis is datetime, or tuple of floats. Default Noneylim (
Union
[Tuple
[float
,float
],Tuple
[datetime64
,datetime64
],None
]) – y limits for the plot. Tuple of floats. Default Noneheight_ratio (
float
) – If you have more than one subplot on a plot, use height ratio to determine how high each subplot should be. For example, if you set height_ratio = 0.75 for the first subplot and 0.25 for the second, the first will be 3 times taller than the second one. Default 1.0display_legend (
bool
) – Whether to show a legend on the plot. Default Truelegend_loc (
str
) – Location for the legend. Default ‘best’log_y (
bool
) – Whether the y axis should be logarithmic. Default Falsey_tick_format (
Optional
[str
]) – Format string to use for y axis labels. For example, you can decide to use fixed notation instead of scientific notation or change number of decimal places shown. Default None
- class pyqstrat.plot.SurfacePlotAttributes(marker='X', marker_size=50, marker_color='red', interpolation='linear', cmap=<matplotlib.colors.LinearSegmentedColormap object>)[source]¶
Bases:
DisplayAttributes
- marker¶
Adds a marker to each point in x, y, z to show the actual data used for interpolation. You can set this to None to turn markers off.
- Type
str
- interpolation¶
Can be ‘linear’, ‘nearest’ or ‘cubic’ for plotting z points between the ones passed in. See scipy.interpolate.griddata for details
- Type
str
- cmap¶
Colormap to use (default matplotlib.cm.RdBu_r). See matplotlib colormap for details
- Type
matplotlib.colors.Colormap
- cmap: Colormap = <matplotlib.colors.LinearSegmentedColormap object>¶
- interpolation: str = 'linear'¶
- marker: str = 'X'¶
- marker_color: str = 'red'¶
- marker_size: int = 50¶
- class pyqstrat.plot.TimeSeries(name, timestamps, values, display_attributes=None)[source]¶
Bases:
TimePlotData
Data in a subplot where x is an array of numpy datetimes and y is a numpy array of floats
- __init__(name, timestamps, values, display_attributes=None)[source]¶
- Parameters
name (
str
) – Name to show in plot legend
- display_attributes: DisplayAttributes¶
- name: str¶
- reindex(timestamps, fill)[source]¶
Reindex this series given a new array of timestamps, forward filling holes if fill is set to True
- Return type
None
- timestamps: ndarray¶
- class pyqstrat.plot.TradeBarSeries(name, timestamps, o, h, l, c, v=None, vwap=None, display_attributes=None)[source]¶
Bases:
TimePlotData
Data in a subplot that contains open, high, low, close, volume bars. volume is optional.
- __init__(name, timestamps, o, h, l, c, v=None, vwap=None, display_attributes=None)[source]¶
- Parameters
name (
str
) – Name to show in a legend
- display_attributes: DisplayAttributes¶
- name: str¶
- timestamps: ndarray¶
- class pyqstrat.plot.TradeSet(name, trades, display_attributes=None)[source]¶
Bases:
TimePlotData
Data for subplot that contains a set of trades along with marker properties for these trades
- __init__(name, trades, display_attributes=None)[source]¶
- Parameters
name (
str
) – String to display in a subplot legendtrades (
Sequence
[Trade
]) – List of Trade objects to plot
- display_attributes: DisplayAttributes¶
- name: str¶
- timestamps: ndarray¶
- class pyqstrat.plot.VerticalLine(x, name=None, line_type='dashed', color=None)[source]¶
Bases:
object
Draws a vertical line on a subplot where x axis is not a date-time axis
- class pyqstrat.plot.XYData(name, x, y, display_attributes=None)[source]¶
Bases:
PlotData
Data in a subplot that has x and y values that are both arrays of floats
- display_attributes: DisplayAttributes¶
- name: str¶
- class pyqstrat.plot.XYZData(name, x, y, z, display_attributes=None)[source]¶
Bases:
PlotData
Data in a subplot that has x, y and z values that are all floats
- __init__(name, x, y, z, display_attributes=None)[source]¶
- Parameters
name (
str
) – Name to show in plot legend
- display_attributes: DisplayAttributes¶
- name: str¶
- pyqstrat.plot.draw_3d_plot(ax, x, y, z, plot_type='contour', marker='X', marker_size=50, marker_color='red', interpolation='linear', cmap=<matplotlib.colors.LinearSegmentedColormap object>, min_level=nan, max_level=nan)[source]¶
Draw a 3d plot. See XYZData class for explanation of arguments
>>> points = np.random.rand(1000, 2) >>> x = np.random.rand(10) >>> y = np.random.rand(10) >>> z = x ** 2 + y ** 2 >>> if has_display(): ... fig, ax = plt.subplots() ... draw_3d_plot(ax, x = x, y = y, z = z, plot_type = 'contour', interpolation = 'linear');
- Return type
None
- pyqstrat.plot.draw_boxplot(ax, names, values, proportional_widths=True, notched=False, show_outliers=True, show_means=True, show_all=True)[source]¶
Draw a boxplot. See BucketedValues class for explanation of arguments
- Return type
None
- pyqstrat.plot.draw_candlestick(ax, index, o, h, l, c, v, vwap, colorup='darkgreen', colordown='#F2583E')[source]¶
Draw candlesticks given parrallel numpy arrays of o, h, l, c, v values. v is optional. See TradeBarSeries class __init__ for argument descriptions.
- Return type
None
- pyqstrat.plot.draw_date_line(ax, plot_timestamps, date, linestyle, color)[source]¶
Draw vertical line on a subplot with datetime x axis
- Return type
Line2D
- pyqstrat.plot.draw_horizontal_line(ax, y, linestyle, color)[source]¶
Draw horizontal line on a subplot
- Return type
Line2D
- pyqstrat.plot.draw_poly(ax, left, bottom, top, right, facecolor, edgecolor, zorder)[source]¶
Draw a set of polygrams given parrallel numpy arrays of left, bottom, top, right points
- Return type
None
- pyqstrat.plot.draw_vertical_line(ax, x, linestyle, color)[source]¶
Draw vertical line on a subplot
- Return type
Line2D
- pyqstrat.plot.get_date_formatter(plot_timestamps, date_format)[source]¶
Create an appropriate DateFormatter for x axis labels. If date_format is set to None, figures out an appropriate date format based on the range of timestamps passed in
- Return type
- pyqstrat.plot.trade_sets_by_reason_code(trades, marker_props={'backtest end': {'color': 'green', 'size': 50, 'symbol': '*'}, 'enter long': {'color': 'blue', 'size': 50, 'symbol': 'P'}, 'enter short': {'color': 'red', 'size': 50, 'symbol': 'P'}, 'exit long': {'color': 'blue', 'size': 50, 'symbol': 'X'}, 'exit short': {'color': 'red', 'size': 50, 'symbol': 'X'}, 'none': {'color': 'green', 'size': 50, 'symbol': 'o'}, 'roll future': {'color': 'green', 'size': 50, 'symbol': '>'}}, remove_missing_properties=True)[source]¶
Returns a list of TradeSet objects. Each TradeSet contains trades with a different reason code. The markers for each TradeSet are set by looking up marker properties for each reason code using the marker_props argument:
- Parameters
trades (
List
[Trade
]) – We look up reason codes using the reason code on the corresponding ordersmarker_props (
Mapping
[str
,Mapping
]) – Dictionary from reason code string -> dictionary of marker properties. See ReasonCode.MARKER_PROPERTIES for example. Default ReasonCode.MARKER_PROPERTIESremove_missing_properties (
bool
) – If set, we remove any reason codes that dont’ have marker properties set. Default True
- Return type
List
[TradeSet
]
pyqstrat.evaluator module¶
- class pyqstrat.evaluator.Evaluator(initial_metrics)[source]¶
Bases:
object
You add functions to the evaluator that are dependent on the outputs of other functions. The evaluator will call these functions in the right order so dependencies are computed first before the functions that need their output. You can retrieve the output of a metric using the metric member function
>>> evaluator = Evaluator(initial_metrics={'x': np.array([1, 2, 3]), 'y': np.array([3, 4, 5])}) >>> evaluator.add_metric('z', lambda x, y: sum(x, y), dependencies=['x', 'y']) >>> evaluator.compute() >>> evaluator.metric('z') array([ 9, 10, 11])
- __init__(initial_metrics)[source]¶
Inits Evaluator with a dictionary of initial metrics that are used to compute subsequent metrics
- Parameters
initial_metrics (
Dict
[str
,Any
]) – a dictionary of string name -> metric. metric can be any object including a scalar, an array or a tuple
- compute(metric_names=None)[source]¶
Compute metrics using the internal dependency graph
- Parameters
metric_names (
Optional
[Sequence
[str
]]) – an array of metric names. If not passed in, evaluator will compute and store all metrics- Return type
None
- pyqstrat.evaluator.compute_amean(returns, periods_per_year)[source]¶
Computes arithmetic mean of a return array, ignoring NaNs
- Parameters
returns (
ndarray
) – Represents returns at any frequencyperiods_per_year (
int
) – Frequency of the returns, e.g. 252 for daily returns
>>> compute_amean(np.array([0.003, 0.004, np.nan]), 252) 0.882
- Return type
float
- pyqstrat.evaluator.compute_annual_returns(timestamps, returns, periods_per_year)[source]¶
Takes the output of compute_bucketed_returns and returns geometric mean of returns by year
- Return type
Tuple
[ndarray
,ndarray
]- Returns
A tuple with the first element being an array of years (integer) and the second element an array of annualized returns for those years
- pyqstrat.evaluator.compute_bucketed_returns(timestamps, returns)[source]¶
Bucket returns by year
- Return type
Tuple
[Sequence
[int
],Sequence
[ndarray
]]- Returns
- A tuple with the first element being a list of years and the second a list of
numpy arrays containing returns for each corresponding year
- pyqstrat.evaluator.compute_calmar(returns_3yr, periods_per_year, mdd_pct_3yr)[source]¶
Compute Calmar ratio, which is the annualized return divided by max drawdown over the last 3 years
- Return type
float
- pyqstrat.evaluator.compute_dates_3yr(timestamps)[source]¶
Given an array of numpy datetimes, return those that are within 3 years of the last date in the array
- Return type
ndarray
- pyqstrat.evaluator.compute_equity(timestamps, starting_equity, returns)[source]¶
Given starting equity, timestamps and returns, create a numpy array of equity at each date
- Return type
ndarray
- pyqstrat.evaluator.compute_gmean(timestamps, returns, periods_per_year)[source]¶
Compute geometric mean of an array of returns
- Parameters
returns (
ndarray
) – a numpy array of returns, can contain nansperiods_per_year (
float
) – Used for annualizing returns
>>> round(compute_gmean(np.array(['2015-01-01', '2015-03-01', '2015-05-01'], dtype='M8[D]'), np.array([0.001, 0.002, 0.003]), 252.), 6) 0.018362
- Return type
float
- pyqstrat.evaluator.compute_k_ratio(equity, periods_per_year, halflife_years=None)[source]¶
Compute k-ratio (2013 or original versions by Lars Kestner). See https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2230949 We also implement a modification that allows higher weighting for more recent returns.
- Parameters
equity (
ndarray
) – a numpy array of the equity in your accountperiods_per_year (
int
) – 252 for daily valueshalflife_years (
Optional
[float
]) – If set, we use weighted linear regression to give less weight to older returns. In this case, we compute the original k-ratio which does not use periods per year or number of observations If not set, we compute the 2013 version of the k-ratio which weights k-ratio by sqrt(periods_per_year) / nobs
- Return type
float
- Returns
weighted or unweighted k-ratio
>>> np.random.seed(0) >>> t = np.arange(1000) >>> ret = np.random.normal(loc = 0.0025, scale = 0.01, size = len(t)) >>> equity = (1 + ret).cumprod() >>> assert(math.isclose(compute_k_ratio(equity, 252, None), 3.888, abs_tol=0.001)) >>> assert(math.isclose(compute_k_ratio(equity, 252, 0.5), 602.140, abs_tol=0.001))
- pyqstrat.evaluator.compute_mar(returns, periods_per_year, mdd_pct)[source]¶
Compute MAR ratio, which is annualized return divided by biggest drawdown since inception.
- Return type
float
- pyqstrat.evaluator.compute_maxdd_date(rolling_dd_dates, rolling_dd)[source]¶
Compute date of max drawdown given numpy array of timestamps, and corresponding rolling dd percentages
- Return type
datetime64
- pyqstrat.evaluator.compute_maxdd_date_3yr(rolling_dd_3yr_timestamps, rolling_dd_3yr)[source]¶
Compute max drawdown date over the last 3 years
- Return type
datetime64
- pyqstrat.evaluator.compute_maxdd_pct(rolling_dd)[source]¶
Compute max drawdown percentage given a numpy array of rolling drawdowns, ignoring NaNs
- Return type
float
- pyqstrat.evaluator.compute_maxdd_pct_3yr(rolling_dd_3yr)[source]¶
Compute max drawdown percentage over the last 3 years
- Return type
float
- pyqstrat.evaluator.compute_maxdd_start(rolling_dd_dates, rolling_dd, mdd_date)[source]¶
Compute date when max drawdown starts, given numpy array of timestamps corresponding rolling dd percentages and date of the max draw down
- Return type
datetime64
- pyqstrat.evaluator.compute_maxdd_start_3yr(rolling_dd_3yr_timestamps, rolling_dd_3yr, mdd_date_3yr)[source]¶
Comput max drawdown start date over the last 3 years
- Return type
datetime64
- pyqstrat.evaluator.compute_num_periods(timestamps, periods_per_year)[source]¶
- Given an array of timestamps, we compute how many periods there are between the first and last element, where the length
of a period is defined by periods_per_year. For example, if there are 6 periods per year, then each period would be approx. 2 months long.
- Parameters
timestamps (np.ndarray of np.datetime64) – a numpy array of returns, can contain nans
periods_per_year (
float
) – number of periods between first and last return
>>> assert(compute_num_periods(np.array(['2015-01-01', '2015-03-01', '2015-05-01'], dtype='M8[D]'), 6) == 2)
- Return type
float
- pyqstrat.evaluator.compute_periods_per_year(timestamps)[source]¶
- Computes trading periods per year for an array of numpy datetime64’s.
e.g. if most of the timestamps are separated by 1 day, will return 252.
- Parameters
timestamps (
ndarray
) – a numpy array of datetime64’s
>>> compute_periods_per_year(np.array(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-09'], dtype='M8[D]')) 252.0 >>> round(compute_periods_per_year(np.array(['2018-01-01 10:00', '2018-01-01 10:05', '2018-01-01 10:10'], dtype='M8[m]')), 2) 72576.05
- Return type
float
- pyqstrat.evaluator.compute_return_metrics(timestamps, rets, starting_equity, leading_non_finite_to_zeros=False, subsequent_non_finite_to_zeros=True)[source]¶
Compute a set of common metrics using returns (for example, of an instrument or a portfolio)
- Parameters
timestamps (np.array of datetime64) – Timestamps for the returns
rets (nd.array of float) – The returns, use 0.01 for 1%
starting_equity (float) – Starting equity value in your portfolio
leading_non_finite_to_zeros (bool, optional) – If set, we replace leading nan, inf, -inf returns with zeros. For example, you may need a warmup period for moving averages. Default False
subsequent_non_finite_to_zeros (bool, optional) – If set, we replace any nans that follow the first non nan value with zeros. There may be periods where you have no prices but removing these returns would result in incorrect annualization. Default True
- Return type
- Returns
An Evaluator object containing computed metrics off the returns passed in. If needed, you can add your own metrics to this object based on the values of existing metrics and recompute the Evaluator. Otherwise, you can just use the output of the evaluator using the metrics function.
>>> timestamps = np.array(['2015-01-01', '2015-03-01', '2015-05-01', '2015-09-01'], dtype='M8[D]') >>> rets = np.array([0.01, 0.02, np.nan, -0.015]) >>> starting_equity = 1.e6 >>> ev = compute_return_metrics(timestamps, rets, starting_equity) >>> metrics = ev.metrics() >>> assert(round(metrics['gmean'], 6) == 0.021061) >>> assert(round(metrics['sharpe'], 6) == 0.599382) >>> assert(all(metrics['returns_3yr'] == np.array([0.01, 0.02, 0, -0.015])))
- pyqstrat.evaluator.compute_returns_3yr(timestamps, returns)[source]¶
Given an array of numpy datetimes and an array of returns, return those that are within 3 years of the last date in the datetime array
- Return type
ndarray
- pyqstrat.evaluator.compute_rolling_dd(timestamps, equity)[source]¶
Compute numpy array of rolling drawdown percentage
- Parameters
timestamps (
ndarray
) – numpy array of datetime64equity (
ndarray
) – numpy array of equity
- Return type
Tuple
[ndarray
,ndarray
]
- pyqstrat.evaluator.compute_rolling_dd_3yr(timestamps, equity)[source]¶
Compute rolling drawdowns over the last 3 years
- Return type
Tuple
[ndarray
,ndarray
]
- pyqstrat.evaluator.compute_sharpe(returns, amean, periods_per_year)[source]¶
Note that this does not take into risk free returns so it’s really a sharpe0, i.e. assumes risk free returns are 0
- Parameters
returns (
ndarray
) – a numpy array of returnsamean (
float
) – arithmetic mean of returnsperiods_per_year (
float
) – number of trading periods per year
>>> round(compute_sharpe(np.array([0.001, -0.001, 0.002]), 0.001, 252), 6) 0.050508
- Return type
float
- pyqstrat.evaluator.compute_sortino(returns, amean, periods_per_year)[source]¶
Note that this assumes target return is 0.
- Parameters
returns (
ndarray
) – a numpy array of returnsamean (
float
) – arithmetic mean of returnsperiods_per_year (
float
) – number of trading periods per year
>>> print(round(compute_sortino(np.array([0.001, -0.001, 0.002]), 0.001, 252), 6)) 0.133631
- Return type
float
- pyqstrat.evaluator.compute_std(returns)[source]¶
Computes standard deviation of an array of returns, ignoring nans
- Return type
float
- pyqstrat.evaluator.display_return_metrics(metrics, float_precision=3, show=True)[source]¶
Creates a dataframe making it convenient to view the output of the metrics obtained using the compute_return_metrics function.
- Parameters
float_precision (
int
) – Change if you want to display floats with more or less significant figures than the default, 3 significant figures.- Return type
DataFrame
- Returns
A one row dataframe with formatted metrics.
- pyqstrat.evaluator.handle_non_finite_returns(timestamps, rets, leading_non_finite_to_zeros, subsequent_non_finite_to_zeros)[source]¶
>>> np.set_printoptions(formatter={'float': '{: .6g}'.format}) >>> timestamps = np.arange(np.datetime64('2019-01-01'), np.datetime64('2019-01-07')) >>> rets = np.array([np.nan, np.nan, 3, 4, np.nan, 5]) >>> handle_non_finite_returns(timestamps, rets, leading_non_finite_to_zeros = False, subsequent_non_finite_to_zeros = True) (array(['2019-01-03', '2019-01-04', '2019-01-05', '2019-01-06'], dtype='datetime64[D]'), array([ 3, 4, 0, 5])) >>> handle_non_finite_returns(timestamps, rets, leading_non_finite_to_zeros = True, subsequent_non_finite_to_zeros = False) (array(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-06'], dtype='datetime64[D]'), array([ 0, 0, 3, 4, 5])) >>> handle_non_finite_returns(timestamps, rets, leading_non_finite_to_zeros = False, subsequent_non_finite_to_zeros = False) (array(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-06'], dtype='datetime64[D]'), array([ 0, 0, 3, 4, 5])) >>> rets = np.array([1, 2, 3, 4, 4.5, 5]) >>> handle_non_finite_returns(timestamps, rets, leading_non_finite_to_zeros = False, subsequent_non_finite_to_zeros = True) (array(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05', '2019-01-06'], dtype='datetime64[D]'), array([ 1, 2, 3, 4, 4.5, 5]))
- Return type
Tuple
[ndarray
,ndarray
]
pyqstrat.pyqstrat_cpp module¶
- pyqstrat.pyqstrat_cpp.black_scholes_price(call: numpy.ndarray[bool], S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute Euroepean option price :param call: True for a call option, False for a put :type call: bool :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option price
- Return type
float
- pyqstrat.pyqstrat_cpp.cdf(x: numpy.ndarray[numpy.float64]) object ¶
Cumulative density function of normal distribution :param x: random variable :type x: float
- Returns
cdf of the random variable
- Return type
float
- pyqstrat.pyqstrat_cpp.d1(S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
d1 from Black Scholes :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1% :type q: float
- Return type
float
- pyqstrat.pyqstrat_cpp.d2(S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
d2 from Black Scholes :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1% :type q: float
- Return type
float
- pyqstrat.pyqstrat_cpp.delta(call: numpy.ndarray[bool], S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute European option delta :param call: True for a call option, False for a put :type call: bool :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option delta
- Return type
float
- pyqstrat.pyqstrat_cpp.gamma(S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute European option gamma. :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option gamma
- Return type
float
- pyqstrat.pyqstrat_cpp.implied_vol(call: numpy.ndarray[bool], price: numpy.ndarray[numpy.float64], S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute implied volatility for a European option. :param call: True for a call option, False for a put :type call: bool :param price: The option premium :type price: float :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Implied volatility. For 1% we return 0.01
- Return type
float
- pyqstrat.pyqstrat_cpp.rho(call: numpy.ndarray[bool], S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute European option rho. This is Black Scholes formula rho divided by 100 so we get rho per 1% change in interest rate :param call: True for a European call option, False for a put :type call: bool :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option theta
- Return type
float
- pyqstrat.pyqstrat_cpp.theta(call: numpy.ndarray[bool], F: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute European option theta per day. This is Black Scholes formula theta divided by 365 to give us the customary theta per day :param call: True for a call option, False for a put :type call: bool :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option theta
- Return type
float
- pyqstrat.pyqstrat_cpp.vega(S: float, K: float, t: float, r: float, sigma: float, q: float = 0.0) float ¶
Compute European option vega. This is Black Scholes formula vega divided by 100 so we get rho per 1% change in interest rate :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option vega
- Return type
float
pyqstrat.pyqstrat_io module¶
- pyqstrat.pyqstrat_cpp.black_scholes_price(call: numpy.ndarray[bool], S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute Euroepean option price :param call: True for a call option, False for a put :type call: bool :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option price
- Return type
float
- pyqstrat.pyqstrat_cpp.cdf(x: numpy.ndarray[numpy.float64]) object ¶
Cumulative density function of normal distribution :param x: random variable :type x: float
- Returns
cdf of the random variable
- Return type
float
- pyqstrat.pyqstrat_cpp.d1(S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
d1 from Black Scholes :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1% :type q: float
- Return type
float
- pyqstrat.pyqstrat_cpp.d2(S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
d2 from Black Scholes :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1% :type q: float
- Return type
float
- pyqstrat.pyqstrat_cpp.delta(call: numpy.ndarray[bool], S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute European option delta :param call: True for a call option, False for a put :type call: bool :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option delta
- Return type
float
- pyqstrat.pyqstrat_cpp.gamma(S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute European option gamma. :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option gamma
- Return type
float
- pyqstrat.pyqstrat_cpp.implied_vol(call: numpy.ndarray[bool], price: numpy.ndarray[numpy.float64], S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute implied volatility for a European option. :param call: True for a call option, False for a put :type call: bool :param price: The option premium :type price: float :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Implied volatility. For 1% we return 0.01
- Return type
float
- pyqstrat.pyqstrat_cpp.rho(call: numpy.ndarray[bool], S: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute European option rho. This is Black Scholes formula rho divided by 100 so we get rho per 1% change in interest rate :param call: True for a European call option, False for a put :type call: bool :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option theta
- Return type
float
- pyqstrat.pyqstrat_cpp.theta(call: numpy.ndarray[bool], F: numpy.ndarray[numpy.float64], K: numpy.ndarray[numpy.float64], t: numpy.ndarray[numpy.float64], r: numpy.ndarray[numpy.float64], sigma: numpy.ndarray[numpy.float64], q: numpy.ndarray[numpy.float64] = 0.0) object ¶
Compute European option theta per day. This is Black Scholes formula theta divided by 365 to give us the customary theta per day :param call: True for a call option, False for a put :type call: bool :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option theta
- Return type
float
- pyqstrat.pyqstrat_cpp.vega(S: float, K: float, t: float, r: float, sigma: float, q: float = 0.0) float ¶
Compute European option vega. This is Black Scholes formula vega divided by 100 so we get rho per 1% change in interest rate :param S: Spot price. For a future discount the future price using exp(-rt) :type S: float :param K: Strike :type K: float :param t: Time to maturity in years :type t: float :param r: Continuously compounded interest rate. Use 0.01 for 1% :type r: float :param sigma: Annualized volatility. Use 0.01 for 1% :type sigma: float :param q: Annualized dividend yield. Use 0.01 for 1%. Default 0 :type q: float, optional
- Returns
Option vega
- Return type
float
pyqstrat.trade_bars module¶
- class pyqstrat.trade_bars.TradeBars(timestamps, c, o=None, h=None, l=None, v=None, vwap=None)[source]¶
Bases:
object
Used to store OHLCV bars. You must at least supply timestamps and close prices. All other fields are optional.
- timestamp¶
A numpy datetime array with the datetime for each bar. Must be monotonically increasing.
- c¶
A numpy float array with close prices for the bar.
- o¶
A numpy float array with open prices . Default None
- h¶
A numpy float array with high prices. Default None
- l¶
A numpy float array with high prices. Default None
- v¶
A numpy integer array with volume for the bar. Default None
- vwap¶
A numpy float array with the volume weighted average price for the bar. Default None
- __init__(timestamps, c, o=None, h=None, l=None, v=None, vwap=None)[source]¶
Zeroes in o, h, l, c are set to nan
- add_timestamps(timestamps)[source]¶
Adds new timestamps to a market data object.
- Parameters
timestamps (np.array of np.datetime64) – New timestamps to add. Does not have to be sorted or unique
>>> timestamps = np.array(['2018-01-05', '2018-01-09', '2018-01-10'], dtype = 'M8[ns]') >>> c = np.array([8.1, 8.2, 8.3]) >>> o = np.array([9, 10, 11]) >>> trade_bar = TradeBars(timestamps, c, o) >>> new_timestamps = np.array(['2018-01-07', '2018-01-09'], dtype = 'M8[ns]') >>> trade_bar.add_timestamps(new_timestamps) >>> print(trade_bar.timestamps) ['2018-01-05T00:00:00.000000000' '2018-01-07T00:00:00.000000000' '2018-01-09T00:00:00.000000000' '2018-01-10T00:00:00.000000000'] >>> np.set_printoptions(formatter = {'float': lambda x: f'{x:.4f}'}) # After numpy 1.13 positive floats don't have a leading space for sign >>> print(trade_bar.o, trade_bar.c) [9.0000 nan 10.0000 11.0000] [8.1000 nan 8.2000 8.3000]
- Return type
None
- describe(warn_std=10, time_distribution_frequency='15 min', print_time_distribution=False)[source]¶
Describe the bars. Shows an overview, errors and warnings for the bar data. This is a good function to use before running any backtests on a set of bar data.
- Parameters
warn_std (
int
) – See warning functiontime_distribution_frequency (
str
) – See time_distribution functionprint_time_distribution (
bool
) – Whether to print the time distribution in addition to plotting it.
- Return type
None
- errors(display=True)[source]¶
Returns a dataframe indicating any highs that are lower than opens, closes, lows or lows that are higher than other columns Also includes any ohlcv values that are negative
- Return type
Optional
[DataFrame
]
- overview(display=True)[source]¶
Returns a dataframe showing basic information about the data, including count, number and percent missing, min, max
- Parameters
display (
bool
) – Whether to print out the warning dataframe as well as returning it- Return type
DataFrame
- plot(figsize=(15, 8), date_range=None, sampling_frequency=None, title='Price / Volume')[source]¶
Plot a candlestick or line plot depending on whether we have ohlc data or just close prices
- Parameters
figsize (
Tuple
[int
,int
]) – Size of the figure (default (15,8))date_range (
Union
[Tuple
[str
,str
],Tuple
[Optional
[datetime64
],Optional
[datetime64
]],None
]) – A tuple of strings or numpy datetimes for plotting a smaller sample of the data, e.g. (“2018-01-01”, “2018-01-06”)sampling_frequency (
Optional
[str
]) – Downsample before plotting. See pandas frequency strings for possible values.title (
str
) – Title of the graph, default “Price / Volume”
- Return type
None
- resample(sampling_frequency)[source]¶
Downsample the trade bars data into a new bar frequency
- Parameters
sampling_frequency (
str
) – See sampling frequency in pandas- Return type
Optional
[TradeBars
]
- time_distribution(frequency='15 minutes', display=True, plot=True, figsize=None)[source]¶
Return a dataframe with the time distribution of the bars
- Parameters
frequency (
str
) – The width of each bin (default “15 minutes”). You can use hours or days as well.display (
bool
) – Whether to display the data in addition to returning it.plot (
bool
) – Whether to plot the data in addition to returning it.figsize (
Optional
[Tuple
[int
,int
]]) – If plot is set, optional figure size for the plot (default (20,8))
- Return type
DataFrame
- warnings(warn_std=10, display=True)[source]¶
Returns a dataframe indicating any values where the bar over bar change is more than warn_std standard deviations.
- Parameters
warn_std (
int
) – Number of standard deviations to use as a threshold (default 10)display (
bool
) – Whether to print out the warning dataframe as well as returning it
- Return type
DataFrame
- pyqstrat.trade_bars.roll_futures(fut_prices, date_func, condition_func, expiries=None, return_full_df=False)[source]¶
Construct a continuous futures dataframe with one row per datetime given rolling logic
- Parameters
fut_prices (
DataFrame
) – A dataframe containing the columns ‘date’, ‘series’, and any other market data, for example, ohlcv data. Date can contain time for sub-daily bars. The series column must contain a different string name for each futures series, e.g. SEP2018, DEC2018, etc.date_func (
Callable
[[DataFrame
],ndarray
]) – A function that takes the future prices as an input and returns a numpy array of booleans True indicates that the future should be rolled on this date if the condition specified in condition_func is met. This function can assume that we have all the columns in the original market data object plus the same columns suffixed with _next for the potential series to roll over to.condition_func (
Callable
[[DataFrame
],ndarray
]) – A function that takes the future prices as input and returns a numpy array of booleans. True indicates that we should try to roll the future at that row.expiries (
Optional
[DataFrame
]) – An optional dataframe with 2 columns, ‘series’ and ‘expiry’. This should have one row per future series indicating that future’s expiry date. If you don’t pass this in, the function will assume that the expiry column is present in the original dataframe.return_full_df (
bool
) – If set, will return the datframe without removing extra timestamps so you can use your own logic for rolling, including the _next columns and the roll flag
- Return type
DataFrame
- Returns
- A pandas DataFrame with one row per date, which contains the columns in the original md DataFrame and the same columns suffixed with _next
representing the series we want to roll to. There is also a column called roll_flag which is set to True whenever the date and roll condition functions are met.
>>> fut_prices = pd.DataFrame({'timestamp': np.concatenate((np.arange(np.datetime64('2018-03-11'), np.datetime64('2018-03-16')), ... np.arange(np.datetime64('2018-03-11'), np.datetime64('2018-03-16')))), ... 'c': [10, 10.1, 10.2, 10.3, 10.4] + [10.35, 10.45, 10.55, 10.65, 10.75], ... 'v': [200, 200, 150, 100, 100] + [100, 50, 200, 250, 300], ... 'series': ['MAR2018'] * 5 + ['JUN2018'] * 5})[['timestamp','series', 'c', 'v']] >>> expiries = pd.Series(np.array(['2018-03-15', '2018-06-15'], dtype = 'M8[D]'), index = ['MAR2018', 'JUN2018'], name = "expiry") >>> date_func = lambda fut_prices: fut_prices.expiry - fut_prices.timestamp <= np.timedelta64(3, 'D') >>> condition_func = lambda fut_prices: fut_prices.v_next > fut_prices.v >>> df = roll_futures(fut_prices, date_func, condition_func, expiries) >>> assert np.max(df[df.series == 'MAR2018'].timestamp.values == np.datetime64('2018-03-14')) >>> assert(np.max(df[df.series == 'JUN2018'].timestamp.values) == np.datetime64('2018-03-15'))
pyqstrat.interactive_plot module¶
- class pyqstrat.interactive_plot.InteractivePlot(data, labels=None, transform_func=<pyqstrat.interactive_plot.SimpleTransform object>, create_selection_widgets_func=<function create_selection_dropdowns>, dim_filter_func=<function simple_dimension_filter>, data_filter_func=<function simple_data_filter>, stat_func=<pyqstrat.interactive_plot.MeanWithCI object>, plot_func=<pyqstrat.interactive_plot.LineGraphWithDetailDisplay object>, display_form_func=<function display_form>, debug=False)[source]¶
Bases:
object
Creates a multidimensional interactive plot off a dataframe.
- __init__(data, labels=None, transform_func=<pyqstrat.interactive_plot.SimpleTransform object>, create_selection_widgets_func=<function create_selection_dropdowns>, dim_filter_func=<function simple_dimension_filter>, data_filter_func=<function simple_data_filter>, stat_func=<pyqstrat.interactive_plot.MeanWithCI object>, plot_func=<pyqstrat.interactive_plot.LineGraphWithDetailDisplay object>, display_form_func=<function display_form>, debug=False)[source]¶
- Parameters
data (
DataFrame
) – The pandas dataframe to use for plottinglabels (
Optional
[Dict
[str
,str
]]) – A dict where column names from the dataframe are mapped to user friendly labels. For any column names not found as keys in this dict, we use the column name as the label. Default Nonedim_filter_func (
Callable
[[DataFrame
,str
,List
[Tuple
[str
,Any
]]],ndarray
]) – A function that generates the values of a dimension based on other dimensions. For example, if the user chooses “Put Option” in a put/call dropdown, the valid strikes could change in a Strike dropdown that follows. Default simple_dimension_filterdata_filter_func (
Callable
[[DataFrame
,List
[Tuple
[str
,Any
]]],DataFrame
]) – A function that filters the data to plot. For example, if the user chooses “Put Option” in a put/call dropdown, we could filter the dataframe to only include put options. Default simple_data_filterstat_func (
Callable
[[DataFrame
,str
,str
,str
],List
[Tuple
[str
,DataFrame
,Dict
[Any
,DataFrame
]]]]) – Once we have filtered the data, we may need to plot some statistics, such as mean and confidence intervals. In this function, we compute these statistics. Default MeanWithCI()plot_func (
Callable
[[str
,str
,List
[Tuple
[str
,DataFrame
,Dict
[Any
,DataFrame
]]]],List
[Widget
]]) – A function that plots the data. This could also display detail data used to compute the statistics associated with each data point.display_form_func (
Callable
[[Sequence
[Widget
],bool
],None
]) – A function that displays the form given a list of plotly widgets (including the graph widget)debug – Dont clear forms if this is true so we can see print output
- create_pivot(xcol, ycol, zcol, dimensions)[source]¶
Create the initial pivot :type xcol:
str
:param xcol: Column name to use as the x axis in the DataFrame :type ycol:str
:param ycol: Column name to use as the y axis in the DataFrame :type zcol:str
:param zcol: Column name to use for z-values. Each zvalue can be used for a different trace within this plot. For example, a columncalled “option_type” could contain the values “American”, “European”, “Bermudan” and we could plot the data for each type in a separate trace
- Parameters
dimensions (
Dict
[str
,Any
]) – The column names used for filter dimensions. For example, we may want to filter by days to expiration and put/call The key the column name and the value is the initial value for that column. For example, in a dropdown for Put/Call we may want “Put” to be the initial value set in the dropdown. Set to None if you don’t care what initial value is chosen.- Return type
None
- class pyqstrat.interactive_plot.LineConfig(color=None, thickness=nan, secondary_y=False, marker_mode='lines+markers', show_detail=True)[source]¶
Bases:
object
- __init__(color=None, thickness=nan, secondary_y=False, marker_mode='lines+markers', show_detail=True)¶
- color: Optional[str] = None¶
- marker_mode: str = 'lines+markers'¶
- secondary_y: bool = False¶
- show_detail: bool = True¶
- thickness: float = nan¶
- class pyqstrat.interactive_plot.LineGraphWithDetailDisplay(display_detail_func=<pyqstrat.interactive_plot.SimpleDetailTable object>, line_configs={}, title=None, hovertemplate=None, debug=False)[source]¶
Bases:
object
Draws line graphs and also includes a detail pane. When you click on a point on the line graph, the detail pane shows the data used to compute that point.
- __call__(xaxis_title, yaxis_title, line_data)[source]¶
Draw the plot and also set it up so if you click on a point, we display the data used to compute that point. :type line_data:
List
[Tuple
[str
,DataFrame
,Dict
[Any
,DataFrame
]]] :param line_data: The zvalue, plot data, and detail data for each line to draw. The plot data must havex as the first column and y as the second column
- Return:
A list of widgets to draw. In this case, a figure widget and a output widget which contains the detail display
- Return type
List
[Widget
]
- __init__(display_detail_func=<pyqstrat.interactive_plot.SimpleDetailTable object>, line_configs={}, title=None, hovertemplate=None, debug=False)[source]¶
- Parameters
display_detail_func (
Callable
[[Widget
,DataFrame
,bool
],None
]) – A function that displays the data on the detail pane. Default SimpleDetailTableline_configs (
Dict
[str
,LineConfig
]) – Configuration of each line. The key in this dict is the zvalue for that line. Default {}title (
Optional
[str
]) – Title of the graph. Default Nonehovertemplate (
Optional
[str
]) – What to display when we hover over a point on the graph. See plotly hovertemplate
- class pyqstrat.interactive_plot.MeanWithCI(mean_func=<function nanmean>, ci_level=0)[source]¶
Bases:
object
Computes mean (or median) and optionally confidence intervals for plotting
- class pyqstrat.interactive_plot.SimpleDetailTable(colnames=None, float_format='{:.4g}', min_rows=100, copy_to_clipboard=True)[source]¶
Bases:
object
Displays a pandas DataFrame under a plot that contains the data used to compute a statistic of y for each x, y pair
- __call__(detail_widget, data, debug=False)[source]¶
- Parameters
detail_widget (
Widget
) – The widget to display the data indata (
DataFrame
) – The dataframe to display
- Return type
None
- __init__(colnames=None, float_format='{:.4g}', min_rows=100, copy_to_clipboard=True)[source]¶
- Parameters
colnames (
Optional
[List
[str
]]) – List of column names to display. If None we display all columns. Default Nonefloat_format (
str
) – Format for each floating point column. Default {:.4g}min_rows (
int
) – Do not truncate the display of the table before this many rows. Default 100copy_to_clipboard (
bool
) – If set, we copy the dataframe to the clipboard. On linux, you must install xclip for this to work
- class pyqstrat.interactive_plot.SimpleTransform(transforms=None)[source]¶
Bases:
object
Initial transformation of data. For example, you might add columns that are quantiles of other columns
- pyqstrat.interactive_plot.create_selection_dropdowns(dims, labels, update_form_func)[source]¶
Create a list of selection widgets
- Return type
Dict
[str
,Any
]
- pyqstrat.interactive_plot.on_widgets_updated(change, update_form_func, selection_widgets)[source]¶
Callback called by plotly when widgets are updated by the user.
- Return type
None
- pyqstrat.interactive_plot.percentile_buckets(a, n=10)[source]¶
>>> np.random.seed(0) >>> a = np.random.uniform(size=10000) >>> assert np.allclose(np.unique(percentile_buckets(a)), np.arange(0.05, 1, 0.1), atol=0.01)
- Return type
ndarray
pyqstrat.markets module¶
- class pyqstrat.markets.EminiFuture[source]¶
Bases:
object
- calendar = <pyqstrat.holiday_calendars.Calendar object>¶
- static get_current_symbol(curr_date)[source]¶
>>> assert(EminiFuture.get_current_symbol(datetime.date(2019, 3, 14)) == 'ESH9') >>> assert(EminiFuture.get_current_symbol(datetime.date(2019, 3, 15)) == 'ESM9') >>> assert(EminiFuture.get_current_symbol(datetime.date(2020, 3, 14)) == 'ESH0')
- Return type
str
- static get_expiry(fut_symbol)[source]¶
>>> assert(EminiFuture.get_expiry('ESH8') == np.datetime64('2018-03-16T08:30'))
- Return type
datetime64
- class pyqstrat.markets.EminiOption[source]¶
Bases:
object
- calendar = <pyqstrat.holiday_calendars.Calendar object>¶
- pyqstrat.markets.future_code_to_month(future_code)[source]¶
Given a future code such as “X”, return the month abbreviation, such as “nov”
- Parameters
future_code (str) – the one letter future code
>>> future_code_to_month('X') 'nov'
- Return type
str