Module engine
This module contains the logic to run the backtest.
Sub-modules
backtest.engine.accountbacktest.engine.analyserbacktest.engine.backtestbacktest.engine.backtestResultbacktest.engine.brokerbacktest.engine.cashControllerbacktest.engine.functional-
This module contains multiple helper function to execute a backtest.
backtest.engine.metadatabacktest.engine.portfoliobacktest.engine.recordbacktest.engine.strategybacktest.engine.time_resolution_extendersbacktest.engine.tradebacktest.engine.transactionbacktest.engine.tsDatabacktest.engine.utils
Classes
class Account (initial_cash: float = 100000, allow_debt: bool = False)-
Object representing the bank account of the strategy. This object keeps track of the cash available in the account, the collateral used in the account and the transactions made by the strategy.
Attributes
available_cash- The amount of cash available in the account. This is the amount of cash that can be used to buy securities.
collateral- The amount of money that is currently being used as collateral.
transactions- The transactions made by the strategy.
Static methods
def load_state(dict_data: dict)-
This method load a Account object from a dictionary.
Args:
dict_data: The dictionary to load fromReturns:
- The Account object
Methods
def add_collateral(self, amount: float, dt: datetime.datetime, message: str = 'Sold short')-
Adds collateral to the account. This is the amount of money held as collateral and cannot be used. This method could be used when selling short a position.
Args:
amount: Value of collateral.
dt: datetime of the update
message: Reason of the update. Can be, for example: "Step update", "Enter short position for {ticker}", etc.Returns:
- None
Raises:
RuntimeError: If the amount of collateral is bigger than the current cash in the account. def get_cash(self)-
The amount of cash available in the account. This is the amount of cash that can be used to buy securities. total_cash - collateral = cash
Returns:
- available cash
def get_state(self) ‑> dict-
This method export the account object to a JSONable dictionary.
Returns:
- The object state as a dictionary
def get_total_cash(self)-
The total amount of cash in the account. Not deducing collateral. This include cash that cannot be used to buy securities.
Returns:
- Total cash
def get_transactions(self)-
Return a deepcopy of the transactions list.
Returns:
- The transactions list
def remove_collateral(self, amount: float, dt: datetime.datetime, message: str = 'Bought back short')-
Removes collateral from the account. This is the amount of money held as collateral and cannot be used. This method could be used when buying back a short position.
Args:
amount: Value of collateral.
dt: datetime of the update
message: Reason of the update. Can be, for example: "Step update", "Enter short position for {ticker}", etc.Returns:
- None
Raises:
RuntimeError: If the amount of collateral is bigger than the current cash in the account. def update_collateral(self, amount: float, dt: datetime.datetime, message: str = 'Step update')-
Updates the amount of collateral in the account. This is the amount of money held as collateral and cannot be used. This should be updated at each steps because it should be dependent to the current value of the assets. Raise a RuntimeError if the amount of collateral is bigger than the current worth of the account.
Args:
amount: Value of collateral.
dt: datetime of the update
message: Reason of the update. Can be, for example: "Step update", "Enter short position for {ticker}", etc.Returns:
- None
class CollateralUpdate (amount: float, dt: datetime.datetime, message: str, collateral_update_type: CollateralUpdateType)-
Data class holding info about a collateral update
Args:
amount: The amount frozen in the account as collateral (Cannot be used to buy securities)
dt: The datetime of the update.
message: A message explaining the reason of the update. (Useful for debugging the strategy)
collateral_update_type: The type of update. Can be ADD, REMOVE or UPDATEStatic methods
def load(data: dict)-
This method load a CollateralUpdate object from a dictionary.
Args:
data: The dictionary to load fromReturns:
- The CollateralUpdate object
Methods
def export(self) ‑> dict-
This method export the trade order object to a JSONable dictionary.
Returns:
- The object's state as a dictionary
class CollateralUpdateType (*args, **kwds)-
[Enum] The type of collateral update. Can be:
- ADD
- REMOVE
- UPDATE
Parent
- enum.Enum
Class variables
var ADDvar REMOVEvar UPDATE
class Backtest (data: List[Dict[str, TSData]], strategy: Strategy, *, metadata: Metadata = <backtest.engine.metadata.Metadata object>, market_index: TSData = None, main_timestep: int = 0, initial_cash: float = 100000, commission: float = None, relative_commission: float = None, margin_interest: float = 0, min_initial_margin: float = 50, min_maintenance_margin: float = 25, liquidation_delay: int = 2, min_initial_margin_short: float = 50, min_maintenance_margin_short: float = 25, broker: Type[Broker] = backtest.engine.broker.Broker, account: Type[Account] = backtest.engine.account.Account, window: int = 50, default_marginable: bool = False, default_shortable: bool = False, risk_free_rate: float = 1.5, default_short_rate: float = 1.5, sell_at_the_end: bool = True, cash_controller: CashControllerBase = <backtest.engine.cashController.CashControllerBase object>, verbose=3, time_res_extender: Optional[TimeResExtender] = None, indicators: Union[IndicatorSet, List[IndicatorSet], Dict[int, IndicatorSet]] = IndicatorSet(n_indicators=0))-
Args:
data: The data on which to run the backtest. It is a list of dictionaries where each dictionary represents a group of time series data. The key is the ticker and the value is the TSData object. IMPORTANT: The length of each time series (charts) must be the same with the same index. If they are not, you need to pad the data with nan.
strategy: The strategy to test
metadata: A metadata object. This is useful to store information about the backtest to add context.
market_index: The TSData object containing the reference market index. (Used to compare the strategy performances to the market)
main_timestep: The index of the timeseries data in data list to use as the main series. i.e. the frequency at which the strategy is run. The other timeseries will be passed to the strategy as additional data. For example, if our data is a list of two dictionaries, the first one containing hourly data and the second one containing daily data, and we extend the daily data to weekly data, we would set main_timestep to 1. (The second dictionary) to run our strategy at each open market days.
initial_cash: The initial cash in bank account
commission: The absolute commission. In $ per trade
relative_commission: The relative commission. In % of the trade value. Example: 5% would be 5
margin_interest: The interest rate on margin. In % of the margin value. Example: 5% would be 5
min_initial_margin: The minimum initial margin. In % of the trade value. Example: 5% would be 5
min_maintenance_margin: The minimum maintenance margin. In % of the trade value. Example: 5% would be 5
liquidation_delay: The delay before liquidating a position in margin call. In timestep. Example, if the delay is 2 and the main time resolution is daily, the position will be liquidated 2 days
min_initial_margin_short: The minimum initial margin for short positions. In % of the trade value.
min_maintenance_margin_short: The minimum maintenance margin for short positions. In % of the trade value.
broker: The Broker class to use. This is useful to use a custom broker. The broker class must inherit from the Broker class.
account: The Account class to use. This is useful to use a custom account. The account class must inherit from the Account class.
window: The lookback period for the strategy. The number of datapoint to pass to the strategy at each timestep. (The number of datapoint in the main timestep. There might be more or less for others)
default_marginable: In case there is no column "Marginable" in the data, this value will be used to know if the security is marginable.
default_shortable: In case there is no column "Shortable" in the data, this value will be used to know if the security is shortable.
risk_free_rate: The risk-free rate in %. Used to calculate performance ratios like the Sharpe ratio.
default_short_rate: The short rate in % in case there is no column 'Short_rate' in the data.
sell_at_the_end: Whether to sell every open position at the end or not. If True, the strategy will sell the positions at the end of the backtest.
cash_controller: A cash controller object to control the money flow in and out of the bank account during the backtest. This is useful to simulate the effect of, for example, weekly deposit or monthly withdrawal.
verbose: 0: No print, 1: Only errors, 2: Errors and warnings, 3: All
time_res_extender: A time resolution extender object. This is useful to add time resolutions to the data
indicators: An Indicator set object. This is useful to add indicators to the data. The indicators are calculated at each timestep and passed to the strategy. It can also be a list with the same length as the number of time resolution. Each element of the list will be an IndicatorSet object to use for the corresponding time resolution. If it is a dictionary, the keys will be the index of the time resolution and the values will be the IndicatorSet object to use for the corresponding time resolution. If a dictionary is used, make sure there is at least a key for the main time resolution. If the streaming parameter is True for one of the IndicatorSet, the streaming will be activated for every supported indicators.Static methods
def default_forge_last_candle(data: List[Dict[str, TSData]], current_time_res: int, timestep: datetime.datetime, main_timestep: int) ‑> List[Tuple[float, float, float, float, float, float, str]]-
Forge new candle by cropping the last candle for the data with bigger time resolution than the main timestep to avoid peeking into the future. (Data leaking) How this default method works:
For each Tickers: 1. Find the last candle compared to current time step with the current resolution. (Get index and Open) 2. Find the last candle for the ticker with main resolution. (Get index and Close) 3. Using the main resolution, get the series between the beginning of the candle (Current resolution) and the current timestep. (This will be a series of intra-candle data) This is where it can get tricky because, depending on your data, the start idx (computed in step 1) might not align with any timesteps of the series in the main resolution. In this default method, we will use the next candle the nearest of the desired start idx of the main resolution data. (Default behavior of pandas) 4. Get High by computing the max of the maxes of the intra-candle data and the Low by computing the min of the mins of the intra-candle data. The volume is obtained by summing the volume of the intra-candle data. 5. Return the new candle by using computed High Low Open Close and Volume.
DO NOT OVERRIDE THIS METHOD: If you need to override a candle forging method, override the method 'forge_last_candle' instead.
Args:
data: The data
current_time_res: The current time resolution (to forge)
timestep: The current timestep
main_timestep: The main timestepReturns:
- A list of the forged candles: List[Tuple[Open, High, Low, Close, Volume, Stock Split, ticker]]
def run_indicator(data: pandas.core.frame.DataFrame, previous_data: Optional[pandas.core.frame.DataFrame], indicators: IndicatorSet, streaming: bool, bigger_res: bool = False) ‑> pandas.core.frame.DataFrame-
Run the indicators on a single chart.
Args:
data: The chart data OHLCV
previous_data: The previously cached data. Used when streaming is True. If streaming is False, this parameter is ignored. This should be a dataframe with the same index as the data. This means that the indicators points that needs to be calculated should be nan, and one already calculated should be the previously calculated values. The columns names should be the output columns names of the indicators.
indicators: The indicatorSet to use.
streaming: Whether to use the streaming capabilities of the indicators or not.
bigger_res: Whether we are computing the indicator for a bigger time resolution or not. If True and we are in streaming mode, the last cache datapoint will be set to nan in order to recompute it.Returns:
- The new data
def stadardize_timesteps(timesteps_list: List[datetime.datetime]) ‑> List[datetime.datetime]-
Optionnaly reformat timesteps_list. Can be useful when indexes are variable across stocks
Args:
timesteps_list: The list of timestepsReturns:
- The reformatted list of timesteps
Methods
def apply_indicators(self, data: List[Record], time_res_idx: int, bigger_res: bool = False) ‑> List[Record]-
Apply the indicators to the data (All tickers in time res)
Args:
data: The list of records to apply the indicators to
time_res_idx: The current time resolution
bigger_res: Whether we are computing the indicator for a bigger time resolution or not. If True and we are in streaming mode, the last cache datapoint will be set to nan in order to recompute it.Returns:
- The updated data
def forge_last_candle(self, data: List[Dict[str, TSData]], prepared_data: List[List[Record]], current_time_res: int, timestep: datetime.datetime) ‑> List[Tuple[float, float, float, float, float, float, str]]-
Forge new candle by cropping the last candle for the data with bigger time resolution than the main timestep to avoid peeking into the future. (Data leaking) How this default method works: (Read the warning below if your data contains higher resolution than main res)
For each Tickers: 1. Find the last candle compared to current time step with the current resolution. (Get index and Open) 2. Find the last candle for the ticker with main resolution. (Get index and Close) 3. Using the main resolution, get the series between the beginning of the candle (Current resolution) and the current timestep. (This will be a series of intra-candle data) This is where it can get tricky because, depending on your data, the start idx (computed in step 1) might not align with any timesteps of the series in the main resolution. In this default method, we will use the next candle the nearest of the desired start idx of the main resolution data. (Default behavior of pandas) 4. Get High by computing the max of the maxes of the intra-candle data and the Low by computing the min of the mins of the intra-candle data. The volume is obtained by summing the volume of the intra-candle data. 5. Return the new candle by using computed High Low Open Close and Volume.
Important
If you need this method in your setup, you should override it since it may not work for your setup. In fact, it is hard to forge new candles for any arbitrary time resolution from discrete timeseries where timesteps might not correctly align. You should take this into account when making this method.
TO OVERRIDE THIS METHOD: Just override it like any other method. You can also use the default method by calling 'self.default_forge_last_candle' and complement it. To suppress the warning, you can override this method by only calling the default 'self.default_forge_last_candle'
Args:
data: The data
prepared_data: The already prepared data.
current_time_res: The current time resolution
timestep: The current timestepReturns:
- A list of the forged candles: List[Tuple[Open, High, Low, Close, Volume, Stock Split, ticker]]
def run(self) ‑> BackTestResult-
Run the backtest simulation with the given data and strategy. It will show a progress bar showing the current progress. It will save the results and all the statistics into a BackTestResult object in the results attribute, or returned value of this method.
Returns:
- BackTestResult object containing all the results, statistics, debug info, etc.
class BackTestResult (strategy_name: str, metadata: Metadata, start: datetime.datetime, end: datetime.datetime, intial_cash: float, added_cash: float, market_index: Optional[numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]], broker: Broker, account: Account, risk_free_rate: float = 1.5)-
This class is used to store the result of a backtest. It contains all the information about the backtest
Args:
strategy_name: The name of the strategy
metadata: The metadata object
start: Start date of the backtest data
end: End date of the backtest data
intial_cash: The initial cash of the account
added_cash: The cash added to the account (or removed) with the CashController
market_index: The market index time series (Price/score evolution across time)
broker: The broker object used to backtest the strategy
account: The account object used to backtest the strategy
risk_free_rate: The risk free rate used to compute the ratios [%]. (Usually the estimated policy rate)Static methods
def load(path: str)-
Load a backtest result from a JSON file
Args:
path: The path to the backtest result fileReturns:
- The backtest result
def load_state(data: dict)-
Load a backtest result from a state dictionary
Args:
data: The state dictionaryReturns:
- The backtest result
def strided_arr(a: numpy.ndarray, window: int)-
Create a strided array to compute the rolling window of an array
Args:
a: The array
window: The window sizeReturns:
- The strided array. Shape(len(a) - window + 1, window)
Methods
def compute_calmar_ratio(self, yearly_max_drawdown: pandas.core.series.Series) ‑> Optional[float]-
Compute the calmar ratio of the strategy
Args:
yearly_max_drawdown: The yearly maximum drawdown of the strategyReturns:
- The calmar ratio of the strategy
def compute_sharp_ratio(self, risk_free_rate) ‑> float-
Compute the sharp ratio of the strategy on a weekly basis
Args:
risk_free_rate: The risk free rate or MAR (Minimum acceptable return)Returns:
- The sharp ratio of the strategy
def compute_sortino_ratio(self, risk_free_rate) ‑> float-
Compute the sortino ratio of the strategy on a weekly basis
Args:
risk_free_rate: The risk free rate or MAR (Minimum acceptable return)Returns:
- The sortino ratio of the strategy
def get_drawdown(self, equity_history: numpy.ndarray, equity_timestamps: numpy.ndarray, window: Union[datetime.timedelta, int] = datetime.timedelta(days=365)) ‑> numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]]-
Get the maximum drawdown of the strategy for each timestep (Causally - so looking back in time)
Args:
equity_history: The equity history of the strategy (Worth of the portoflio evolution over time)
equity_timestamps: The timestamps of the equity history
window: The lookback window to use to compute the drawdownReturns:
- A time series of the maximum drawdown of the strategy for each time steps
def get_ohlc(self, period: Period)-
Return a OHLC dataframe of the equity history corresponding to the period.
Args:
period: The period to use to make the OHLC dataframeReturns:
- The OHLC dataframe
def save(self, path: str)-
Save the backtest result to a JSON file with the .bktst extension if none is provided. About the .bktst extension: This is the fileformat for a backtest result. It is a JSON file that contains all the information about the backtest. It is a human readable file that can be used to share backtest results with other people. Also, it can be loaded by this module so that the backtest result can be analyzed later.
Args:
path: The path to save the backtest result. If no extension is provided, the .bktst extension will be added.Returns:
- None
def toAnalyser(self, data: List[Dict[str, TSData]])-
Convert the backtest result to an analyser object to visualize the backtest results
Returns:
- The analyser object
class Broker (bank_account: Account, commission: float = None, relative_commission: float = None, margin_interest: float = 0, min_initial_margin: float = 0.5, min_maintenance_margin: float = 0.25, liquidation_delay: int = 2, min_initial_margin_short: float = 0.5, min_maintenance_margin_short: float = 0.25)-
When using margin, you need to add a column in the data called 'marginable' that is bool corresponding if a stock can have margin or not. Note: If there is not enough cash in the account when monthly fees are deduced, the strategy fills a bankruptcy, and the simulation stops.
Args:
bank_account: The bank account holding cash and collateral with the initial cash set.
commission: The commission to be paid for each trade. This parameter cannot be set if relative_commission is set. And vice versa. If commission and relative_commission are both None, the commission is set to 0.
relative_commission: The commission to be paid for each trade as a ratio (0-1) of the trade value. This parameter cannot be set if commission is set. And vice versa.
margin_interest: The margin interest rate. It is the interest rate charged on borrowed money. It is calculated daily and charged monthly.
min_initial_margin: The initial margin required to buy a stock on margin. It is a ratio (0-1) of the stock's value. Example: 50% initial margin is 0.5
min_maintenance_margin: The minimum margin required to keep a stock on margin before a margin call. It is a ratio (0-1) of the stock's value. Example: 25% maintenance margin is 0.25
liquidation_delay: The time a margin call has to be active before the broker liquidate positions to pay the margin call. (Must be grater than 0, and an int)
min_initial_margin_short: The minimum initial margin required to sell a stock short. It is a ratio (0-1)
min_maintenance_margin_short: The minimum maintenance margin required to keep a stock short before a margin call. It is a ratio (0-1) of the stock's value.Raises:
ValueError: If both commission and relative_commission are set.
ValueError: If relative_commission is not None and not between 0 and 1
ValueError: If commission is not None and smaller than 0
ValueError: If margin_interest is not between 0 and 1
ValueError: min_initial_margin and min_maintenance_margin are not between 0 and 1
ValueError: If min_maintenance_margin_short and min_initial_margin_short are not between 0 and 1
ValueError: If min_maintenance_margin is greater than or equal to min_initial_margin
ValueError: If min_maintenance_margin_short is greater than or equal to min_initial_margin_shortStatic methods
def compute_dividend_payout(position: Position, div_freq: DividendFrequency, dividends: float) ‑> float-
Compute the dividend payout of a long position
Args:
position: The position to calculate dividend payout
div_freq: The frequency that the security is paying dividends.
dividends: The actual dividends payout for 1 share and for the period in div_freq.Returns:
- Dividend payout
Raises:
RuntimeError: If the position is not long def load_state(data: dict, account: Account)-
Load a broker from a state dictionary
Args:
data: The state dictionary
account: The account to which the broker is linked (Loaded by the BacktestResult object)Returns:
- The broker
Instance variables
var pending_orders : List[TradeOrder]-
Return a copy of the pending orders
Methods
def buy_long(self, ticker: str, amount: int, amount_borrowed: int = 0, expiry: Optional[datetime.datetime] = None, price_limit: Tuple[Optional[float], Optional[float]] = (None, None))-
The strategy calls this method to open a long position. The position can be bought on margin.
Args:
ticker: The ticker of the security to buy
amount: The amount of shares to buy
amount_borrowed: The amount of shares to buy on margin. (Won't be charged in the account)
expiry: The expiry date of the order. If the order is not executed before the expiry date, it is automatically cancelled. If the expiry date is None, the order is never cancelled.
price_limit: The price limit of the order. The first value of the tuple is the maximum price to buy.Meaning the order will be executed if the price is lower or equal to the limit. The second value is the minimumprice to buy. Meaning the order will be executed if the price is higher or equal to the limit. If the limit is(None, None) the order will be executed at the next open price.Returns:
- None
def buy_short(self, ticker: str, amount_borrowed: int = 0, expiry: Optional[datetime.datetime] = None, price_limit: Tuple[Optional[float], Optional[float]] = (None, None))-
The strategy calls this method to close a short position.
Args:
ticker: The ticker of the security to buy
amount_borrowed: The amount of shares to buy back.
expiry: The expiry date of the order. If the order is not executed before the expiry date, it is automatically cancelled. If the expiry date is None, the order is never cancelled.
price_limit: The price limit of the order. The first value of the tuple is the maximum price to buy.Meaning the order will be executed if the price is lower or equal to the limit. The second value is the minimumprice to buy. Meaning the order will be executed if the price is higher or equal to the limit. If the limit is(None, None) the order will be executed at the next open price.Returns:
- None
def get_state(self) ‑> dict-
Get the current state of the broker as a JSONable dictionary (deepcopy
Note
- It doesn't include the account's state.
Returns:
- The broker's state as a dictionary
def get_worth(self, security_names: List[str], current_tick_data: numpy.ndarray) ‑> float-
Get the worth of the portfolio. (Doesn't include the transaction cost as if we would sell the positions)
Formula
worth = cash + sum(long_positions) - sum(short_positions)
where: long_positions = sum(long_position_amount * close_price - debt) short_positions = sum(short_position_amount * close_price) cash: The total cash in portfolio excluding all collateral.
Args:
security_names: A list of all securities where the index of each ticker is the index of the data of the corresponding security in the 'current_tick_data' parameter along the first axis (axis=0).
current_tick_data: An array containing prices of each security for the current step shape(n_securities, 4)Returns:
- worth in dollars
def make_trade(self, order: TradeOrder, security_price: Tuple[float, float, float, float, float], timestamp: datetime.datetime, marginable: bool, shortable: bool) ‑> bool-
This method is call to make trades (convert tradeOrders to trade). Make the trade if price is within limits
Args:
order: TradeOrder
security_price: The security price (Open, High, Low, Close, Splits)
timestamp: The time where securities will be bought (Usually the next step)
marginable: If the security is marginable.
shortable: If the security is shortable.Returns:
- True if the trade was successful (Needs to remove from pending trades) And False otherwise
Raises:
RuntimeError: If the trade cannot be executed because of margin or cash issues. def new_margin_call(self, value: float, message: str = 'missing_funds')-
Create a new margin call and appends it to the other margin calls. Do not forget to remove money from account if necessary. It also add the value to the debt record.
Args:
value: The value that needs to be added to the account to cover margin callReturns:
- None
def remove_margin_call(self, key: str)-
Remove a margin call from the list of margin calls. It also removed the debt in the debt record.
Args:
key: The key of the margin call to removeReturns:
- None
def sell_long(self, ticker: str, amount: int, expiry: Optional[datetime.datetime] = None, price_limit: Tuple[Optional[float], Optional[float]] = (None, None))-
The strategy calls this method to close a long position.
Args:
ticker: The ticker of the security to sell
amount: The amount of shares to sell
expiry: The expiry date of the order. If the order is not executed before the expiry date, it is automatically cancelled. If the expiry date is None, the order is never cancelled.
price_limit: The price limit of the order. The first value of the tuple is the minimum price to sell(Stop loss). Meaning the order will be executed if the price is lower or equal to the limit. The second valueis the maximum price to sell. Meaning the order will be executed if the price is higher or equal to the limit.If the limit is (None, None) the order will be executed at the next open price.Returns:
- None
def sell_short(self, ticker: str, amount_borrowed: int = 0, expiry: Optional[datetime.datetime] = None, price_limit: Tuple[Optional[float], Optional[float]] = (None, None))-
The strategy calls this method to open a short position.
Args:
ticker: The ticker of the security to sell
amount_borrowed: The amount of shares to sell short.
expiry: The expiry date of the order. If the order is not executed before the expiry date, it is automatically cancelled. If the expiry date is None, the order is never cancelled.
price_limit: The price limit of the order. The first value of the tuple is the minimum price to sell.Meaning the order will be executed if the price is lower or equal to the limit. The second value is the maximum price to sell. Meaning the order will be executed if the price is higher or equal to the limit.If the limit is (None, None) the order will be executed at the next open price.Returns:
- None
def tick(self, timestamp: datetime.datetime, next_timestamp, security_names: List[str], current_tick_data: numpy.ndarray, next_tick_data: numpy.ndarray, marginables: numpy.ndarray[typing.Any, numpy.dtype[bool]], dividends: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], div_freq: List[DividendFrequency], short_rates: numpy.ndarray[typing.Any, numpy.dtype[numpy.float32]], last_tick: bool = False)-
The simulation calls this method after the strategy has run. It will calculate interests and margin call if applicable. It will do trades that can be done in the trade queue at the next open.
Args:
timestamp: The date and time of the current step
next_timestamp: The date and time of the next step where orders will be evaluated/bought
security_names: A list of all securities where the index of each ticker is the index of the data of the corresponding security in the 'next_tick_data' parameter along the first axis (axis=0).
current_tick_data: An array of prices of each security for the current step(n_securities, 4) The 4 columns of the array are: Open, High, Low, Close of the next step.
next_tick_data: An array containing prices of each security for the next step shape(n_securities, 4) The 5 columns of the array are: Open, High, Low, Close and Stock Splits of the next step.
marginables: A boolean array of shape (n_securities, 2) [Marginable, Shortable) where True means that the security can be bought on margin / sold short and False means that it cannot be bought on margin / sold short.
dividends: A float array of shape (n_securities, ) containing the dividends of each security for the current step.
div_freq: The frequency that the security is paying dividends.
short_rates: The interest rates for each security that the user held overnight. Shape(n_securities, )
last_tick: Whether it is the last tick of the simulation. If it is, the broker will liquidate all positions and charge interests.Returns:
- None
class BrokerState (margin_calls: Dict[str, MarginCall], bankruptcy: bool, bankruptcy_amount: float = 0)-
Data class to store message from broker to strategy
Static methods
def load(data: dict)-
This method load a broker state object from a dictionary.
Args:
data: The dictionary containing the object stateReturns:
- The object state as a dictionary
Methods
def export(self)-
This method export the broker state object to a JSONable dictionary.
Returns:
- The object state as a dictionary
class MarginCall (time_remaining: int, amount: float)-
Data class to store info about margin calls
Args:
time_remaining: Time remaining in number of steps until liquidation
amount: Amount in $ that needs to be added to account to come out of margin callStatic methods
def load(data: dict)-
This method load a margin call object from a dictionary.
Args:
data: The dictionary containing the object stateReturns:
- The object state as a dictionary
Methods
def export(self) ‑> dict-
This method export the margin call object to a JSONable dictionary.
Returns:
- The object state as a dictionary
class StepState (timestamp: datetime.datetime, worth: float, pending_orders: List[TradeOrder], filled_orders: List[TradeOrder], margin_calls: Dict[str, MarginCall])-
Record the state of the broker at each steps for easier strategy debugging
Args:
timestamp: The date and time of the current step
worth: The worth of the portfolio
pending_orders: The pending orders that were not executed
filled_orders: The orders that were executed at the current step
margin_calls: The margin calls active at the current stepStatic methods
def load(data: dict)-
This method load a step state object from a dictionary.
Args:
data: The dictionary containing the object stateReturns:
- The object state as a dictionary
Methods
def export(self) ‑> dict-
This method export the step state object to a JSONable dictionary.
Returns:
- The object state as a dictionary
class CashControllerBase-
Children of this class are used to control the money flow in and out of the account during the backtest. Each method are called at the beginning of the time period (day, week, month, year) and the user can decide to deposit or withdraw money from the account. For example, If I want to deposit 1000$ every month, I would do it in the every_month method and 1000$ would be deposited at the beginning of every month. To access the account, just use the self.account attribute. However, you must not modify the account in any way. To add or remove money from the account, make your overriden method return the amount of money added(Positive) or removed(Negative) from the account. For example, if you want to deposit 1000$ every month, you would do: override the every_month method and return 1000. If you want to withdraw 1000$ every month, you would do the same thing but return -1000 instead. If you want to do your deposit/withdrawal based on information from your portfolio or your broker, use the attributes: self.broker.portfolio or self.broker.
You also need to return a comment on the transaction that can be None. Check the example below for more information.
Again, if you use the broker, the account or the strategy, Make sure that they aren't modified in any way!
DO NOT override the 'init' method. Instead, override the init method if you need to initialize some variables.
Attributes
broker- The broker object
account- The account object
strategy- The strategy object
transactions- A list of all transactions made by the cash controller
total_deposited- The total amount of money deposited in the account by the cash controller
Example
>>> from backtest.engine import CashControllerBase >>> # Deposit 1000$ in the account if the available cash is below 1000$ (Check every month) >>> class MyCashController(CashControllerBase): ... def every_month(self, timestamp: datetime) -> Tuple[float, Optional[str]]: ... if self.account.available_cash < 1000: ... return 1000, "Fund deposit" ...Parent
- abc.ABC
Methods
def every_day(self, timestamp: datetime.datetime) ‑> Tuple[float, Optional[str]]-
This method is called every day during the backtest.
def every_month(self, timestamp: datetime.datetime) ‑> Tuple[float, Optional[str]]-
This method is called every month during the backtest.
def every_week(self, timestamp: datetime.datetime) ‑> Tuple[float, Optional[str]]-
This method is called every week during the backtest.
def every_year(self, timestamp: datetime.datetime) ‑> Tuple[float, Optional[str]]-
This method is called every year during the backtest.
def init(self, account: Account, broker: Broker, strategy: Strategy)-
Args:
account: The account
broker: The broker [Shoudl not be modified!!]
class SimpleCashController (every_day: float = 0.0, every_week: float = 0.0, every_month: float = 0.0, every_year: float = 0.0)-
This class is a simple cash controller that will deposit ow withdraw a fixed amount of money at the beginning of every period. If a period's amount is 0 (Default), it won't deposit or withdraw funds.
Parent
class Metadata (strategy_name: Optional[str] = None, description: Optional[str] = None, author: Optional[str] = None, version: Optional[str] = None, time_res: Optional[datetime.timedelta] = None, save_code: bool = True, hash_only: bool = True, file_blacklist: Optional[Iterable[str]] = (), code_path: Optional[str] = None)-
This class is meant to contain all the information needed to reproduce the results of the backtest of a startegy Usually, the dataset must be big, so it is recomended to write in the description how to acquire the dataset,or make a script that download it and save the script.
This class contains the metadata of the strategy.
Args:
strategy_name: The name of the strategy. If None, the name of the class will be used.
description: The description of the strategy. It is strongly recommended to write steps on how to reproduce the results here. If description is None, the docstring of the strategy will be used.
author: The author of the strategy. If None, the git author will be used.
version: The version of the strategy. If None, the git commit hash will be used. If no git repository, it will be "Unknown"
time_res: The time resolution. If None, the automatically found time resolution will be saved. It is the task of the broker to provide the time resolution. (Not handled in this class)
save_code: Whether to save the code of the strategy. If True, the code will be saved.
hash_only: Only used if save_code is True. If True, only the hash of the code will be saved. (It can spare storage space)
file_blacklist: Files to not include in the code saved. It is a list of strings with the file paths relative to the current working directory.
code_path: The path to the root folder where to search for the code. Default is the current working directory (If None). If no '*' is present in the path, it will be added at the end to search for py files.Static methods
-
This method return the git author name.
Returns:
- git author name
def load(data: dict)-
This method load the metadata from a dictionary.
Note
The file_blacklist parameter is not loaded (and not saved) for privacy purposes.
Args:
data: The dictionary to load the metadata from.Returns:
- The metadata object
Methods
def export(self) ‑> dict-
This method export the metadata to a JSONable dictionary.
Note
The file_blacklist parameter is not saved (and not loaded) for privacy purposes.
Returns:
- The state of the object as a dictionary
def get_git_commit(self) ‑> str-
This method return the git commit hash.
Returns:
- git commit hash
def init(self, strategy: Strategy, backtest_parameters: Optional[dict] = None, tickers: Optional[List[str]] = None, features: Optional[List[str]] = None, run_duration: Optional[float] = None)-
This method is used to initialize the metadata object from the Backtest object (When the simulation has started)
Args:
strategy: The strategy object. (Used to get its name
backtest_parameters: The parameters of the backtest object (Init paraeters)
tickers: The tickers used in the backtest
features: The features used in the backtest (Columns)
run_duration: The duration of the backtest (in seconds)Returns:
- None
def load_code(self, checksum: bool = True, ignore: Iterable[str] = (), path: str = './**/*.py') ‑> Dict[str, Dict[str, Optional[str]]]-
This method load the code of the strategy.
Args:
path: The path to search for the code. Default is the current working directory. (And ignore venv)
checksum: Whether to return only the checksum of each file.
ignore: Files to ignore when loading the code.Returns:
- The code of the strategy
-
class Portfolio (transaction_cost: float = 10.0, transaction_relative: bool = False, debt_record: Optional[Dict[str, float]] = None)-
This class will have two sub portfolios: long and short. When 'trade' is called, it will add or remove in the appropriate portfolio the security. It will also remember each trades (in a list) to recover the state at each days (For debugging purpose).
Args:
transaction_cost: The cost of a transaction (buy or sell) in $ or in %
transaction_relative: Whether the transaction cost is in percentage relative to transaction cost or fix price
debt_record: The amount of debt used to buy securities: {security: amount}. Passed by reference from broker.Static methods
def load_state(data: dict, debt_record: Dict[str, float])-
Load the state of the portfolio from a dictionary
Args:
data: The dictionary to load from
debt_record: The amount of debt used to buy securities: {security: amount}. Passed by reference from broker.Returns:
- The portfolio object
Instance variables
var long : Dict[str, Position]-
Return the long positions that are not empty (amount > 0)
var short : Dict[str, Position]-
Return the short positions that are not empty (amount > 0)
Methods
def empty(self) ‑> bool-
To check if the portfolio is empty
Returns:
- True if the portfolio is empty, False otherwise
def estimateCost(self, price: float, amount: int, sell: bool = False) ‑> float-
This method can e used by external classes such as Borker to estimate the cost of a trade.
Args:
price: The price of the security
amount: The amount of security in the transaction (Trade)
sell: Whether the trade is a sell or not. If sell, we subtract the transaction cost from the worth.Returns:
- Worth of transaction - transaction cost
def getLong(self) ‑> Dict[str, Position]-
To get what securities are bought long to later calculate interests (When using margin)
Returns:
- Dictionary[security, amount]
def getLongProfit(self, average_buy_price: float, average_sell_price: float, qty: int, ratio_owned: float, debt: float, number_of_entry: int) ‑> Tuple[float, float]-
Calculate the profit made on a long trade
Args:
average_buy_price: The price at which the security was bought
average_sell_price: The price at which the security was sold
qty: The number of shares in the trade
ratio_owned: The ratio of the security held in account that are owned by the investor. (not bought on margin)
debt: The amount of debt used to buy the security
number_of_entry: The number of time the position was entered. (Used only if transaction cost is absolute)Returns:
- The profit (positive) or loss (negative) made on the trade, relative profit in percentage
def getShort(self) ‑> Dict[str, Position]-
To get what securities are sold short to later calculate interests
Returns:
- Dictionary[security, amount]
def getShortProfit(self, average_sell_price: float, average_buy_price: float, qty: int) ‑> Tuple[float, float]-
Calculate the profit made on a short trade
Args:
average_sell_price: The price at which the security was sold
average_buy_price: The price at which the security was bought
qty: The number of shares in the tradeReturns:
- The profit (positive) or loss (negative) made on the trade, relative profit
def get_state(self) ‑> dict-
Return the state of the portfolio. (Make a deep copy)
Returns:
- The state of the portfolio as a dict
def get_trade_count(self, exit_only: bool = True, cutoff: Optional[datetime.datetime] = None) ‑> int-
To get the number of trades made.
Args:
exit_only: If True, Only the trade that exit a position are countedReturns:
- The number of trades
def get_trade_stats(self, cutoff: Optional[datetime.datetime] = None) ‑> dict-
To get the stats for each trade. (Make a deep copy)
Returns:
- The dictionary of trades: { "best_trade": float, # In percentage "worst_trade": float, # In percentage "win_rate": float, # In percentage "avg_trade": float, # In percentage "max_trade_duration": float, # In days "min_trade_duration": float, # In days "avg_trade_duration": float, # In days "profit_factor": float, # Total gains / Total losses "SQN": float, # System Quality Number}
def get_trades(self)-
To get the list of trades. (Make a deep copy)
Returns:
- the list of rades
def split(self, ticker: str, ratio: float)-
Call this method when a stock split occurs. It will update the average price and the amount of the position.
Args:
ticker: The ticker of the security
ratio: The ratio of the split. let's say it is 7:1, then the ratio is 7, 2:3, then the ratio is 2/3Returns:
- None
def trade(self, trade: Trade, *, correction: float = 0.0) ‑> float-
Make a trade and add it to the portfolio.
Note
This class will handle the debt record. It will add the amount borrowed to the debt record when buying long and remove it when selling long.
Args:
trade: Can be BuyLong, SellLong, SellShort, BuyShort
correction: The correction to apply to the price of the trade. It is used to correct the price onlywhile logging the transaction. It could be used when a split happens at the next tick. If the correction is 0,it is ignored.Returns:
- The cash change in account. If negative, withdraw. If positive, deposit.
Raises:
RuntimeError: If the transaction ID is already used def update_time_stock_idx(self, timestep_elapsed: int = 1)-
Call this method to update the time_stock_idx for each position. It will be used to calculate the dividends due to the shareholders.
Args:
timestep_elapsed: The number of timestep elapsed since the last call to this methodReturns:
- None
class Position (ticker: str, amount: int, long: bool, average_price: float, average_filled_time: datetime.datetime, ratio_owned: float = 1.0)-
Data class holding info about a position
Static methods
def load(data: dict)-
Load the object from a dictionary
Args:
data: The dictionary to load fromReturns:
- The object
Methods
def dividends_got_paid(self, timestamp: datetime.datetime)-
Call this method to reset last dividends date. Useful when calculating how much dividends the user should have
Args:
timestamp: The timestamp of dividend paymentReturns:
- None
def export(self) ‑> dict-
Export the position to a dictionary JSONable
Returns:
- The object as a dictionary
def split(self, ratio: float) ‑> None-
Call this method when a stock split occurs. It will update the average price and the amount.
- $new_price = old_price / ratio$
- $new_amount = old_amount * ratio$
Args:
ratio: The ratio of the split. let's say it is 7:1, then the ratio is 7, 2:3, then the ratio is 2/3Returns:
- The two new positions
def update_time_stock_idx(self, timestep_elapsed: int = 1)-
Call this method to update the time_stock_idx. It will be used to calculate the dividends due to the shareholders. Call this method at the end of each day.
Args:
timestep_elapsed: The number of seconds elapsed since the last call to this methodReturns:
- None
class TradeStats (trade: Trade, duration: datetime.timedelta, profit: float, rel_profit: float, ratio_owned)-
This class will hold the stats for a given trade. It will be used to calculate the stats for the whole portfolio
Args:
trade: The trade object (SellLong or BuyShort)
duration: The duration of the trade
profit: The profit made on the trade
rel_profit: The profit made on the trade relative to the amount invested NOT IN PERCENTAGE
ratio_owned: The ratio of the security held in account that are owned by the investor. (not bought on margin)Raises:
ValueError: If the trade type is not SellLong or BuyShort (Doesn't exit a position)Static methods
def load(data: dict)-
Load the object from a dictionary
Args:
data: The dictionary to load fromReturns:
- The object
Methods
def export(self)-
Export the object to a JSONable dictionary Note: The duration is saved in seconds
Returns:
- A dictionary corresponding top the object's state
class Record (chart: Optional[pandas.core.frame.DataFrame], ticker: str, time_res: int, marginable: bool, shortable: bool, div_freq: DividendFrequency, short_rate: float, next_tick: Optional[pandas.core.series.Series] = None)-
This class contains information about a stock and is pass to the strategy.
Args:
chart: The prepared chart of the stock
ticker: The ticker of the stock
time_res: The idx in the list of resolution of the backtest object of the time resolution of the record.
marginable: Whether the stock is marginable
shortable: Whether the stock is shortable
div_freq: The dividend frequency of the stock
short_rate: The short rate of the stock
next_tick: The next tick of the stockInstance variables
var next_tick-
This method is used to get the next tick of the stock.
Returns:
- The next tick of the stock
class Records (records: Union[List[Record], Dict[str, Record]], time_res: datetime.timedelta, time_res_idx: int, window: int)-
Class containing multiple records for a given time resolution. You can access the record like a list with the index of the record being the index of the ticker in the list of tickers. You can also access the record by the string of the ticker like a dictionary. You can iterate over the records like a dictionary (ticker, record). Finally, you can check if a ticker is in the records like a dictionary.
Attributes
records- The records. The keys are the tickers of the securities.
tickers- The tickers of the securities in the same order as the records attribute.
features- The features of the records. It is the columns of the charts.
time_res- The time resolution
time_res_idx- The index of the time resolution in the available_time_res attribute of the backtest object
window- The window size (lookback period) of the records. Used when exporting to numpy.
Implements
getitem, setitem, iter, contains
Args:
records: The records. If a list, it will be converted to a dictionary internally. If a dictionary, the keys will be the tickers of the securities.
time_res: The time resolution
time_res_idx: The index of the time resolution in the available_time_res attribute of the backtest object
window: The window size (lookback period) of the records. Used when exporting to numpy.Methods
def numpy(self) ‑> numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]-
This method will return the charts as a numpy array. The array might contain nan values if the chart is not long enough to fill the window.
Returns:
- A numpy array of the shape (n, w, p) where n is the number of securities, w is the window size and p is the number of features.
def to_list(self) ‑> List[Record]-
Convert the Records object to a list of Record
Returns:
- A list of Record
def update_features(self)-
This method will update the features attribute to the new features set based on the columns of the charts. Assuming all the charts have the same features.
Returns:
- None
class RecordsBucket (records: Union[List[Records], List[Iterable[Record]]], available_time_res: List[datetime.timedelta], main_timestep: int, window: Optional[int] = None)-
Class containing multiple Records objects for all time resolutions. You can access each Records object by their corresponding time resolution or their index in the available_time_res attribute of the backtest object. You can also iterate over the Records objects like a dictionary (time resolution, Records object). To simplify the access of the Records object associated with the main time resolution, you can use the main attribute.
Attributes
records- The Records objects. The keys are the time resolutions.
available_time_res- The available time resolutions
main_timestep- The index of the main time resolution in the available_time_res attribute of the backtest object
Args:
records: The records
available_time_res: The available time resolutionsInstance variables
var main : Records-
Get the main timestep set of records
Returns:
- The main timestep set of records
class Strategy-
This is the base class of strategies. To create a strategy, you should inherit from this class and implement the run method. The run method is called at each time step to compute the strategy. You can also override the init method to add attributes to the strategy. If you do so, you should also override the save and load methods to save the strategy in a different format (by default it is pickle).
Warning
You should not override the init and the call method. The init, and notice it doesn't have the underscores like init, is used to bind the strategy to the backtest object. This is done under the hood. The call method is used to dispatch the data to the run method. Overriding it might ignore some safety checks or statistics calculations.
While implementing the run method:
You SHOULD NOT change the state of the account, the portfolio or the broker with the exception of calling the methods below on the broker object. If you modify the state of one of these objects, you could encounter bugs and false backtest results. The only methods you should call on the broker object are: - broker.buy_long(…) - broker.sell_long(…) - broker.buy_short(…) - broker.sell_short(…)
Attributes
account- The account object
broker- The broker object
available_time_res- The available time resolutions
portfolio- The portfolio object (Alias of broker.portfolio)
Example
>>> class MyStrategy(Strategy): ... def run(self, data, timestep): ... for ticker in data.main.tickers: ... chart = data.main[ticker].chart ... if len(chart) > 2 and F.crossover(chart["MACD"], chart["MACD_SIGNAL"]) and chart["MACD"].iloc[-1] < 0: ... if ticker not in self.broker.portfolio.long: ... self.broker.buy_long(ticker, 500) ... if ticker in self.broker.portfolio.long and F.crossunder(chart["MACD"], chart["MACD_SIGNAL"]): ... self.broker.sell_long(ticker, 500) ...Parent
- abc.ABC
Static methods
def load(path: pathlib.PurePath)-
This method is used to load the state of a strategy from a file. If you would like to save in an other format, you can override this method and the save method.
Args:
path: The path to load the strategy from. (.pkl)
Methods
def init(self, account: Account, broker: Broker, available_time_res: List[datetime.timedelta])-
YOU SHOULD NOT OVERRIDE THIS METHOD
Args:
account: The account object
broker: The broker object
available_time_res: The available time resolutions def run(self, data: RecordsBucket, timestep: datetime.datetime)-
This method is used to compute the strategy at each time step. It is in this method that the strategy logic is implemented.
Args:
data: The data to use for the strategy
timestep: The current time step def save(self, path: pathlib.PurePath)-
This method is used to save the state of the strategy to a file. If you would like to save in another format, you can override this method and the load method.
Note
To avoid saving things twice, we set the account, broker and available_time_res to None before saving. Only the other attributes will be saved. (If any)
Args:
path: The path to save the strategy (.pkl)
class BasicExtender (period: Union[TimePeriod, str])-
This class provide an easy top implement extender for basic time resolutions such as 30 minutes, 1 hour, 4 hours, 1 day, 1 week, and 1 month. It assumes to have has main timestep (In the backtest object) a time resolution smaller than the value chose. For example, if the main timestep is 1 day, it will not work to extend the data to 30 minutes or 4h. If you have multiple static timestep that you want to extend, you can override the extend method to handle this case, or directly derive a new class from TimeResExtender.
Example
>>> extender = BasicExtender(TimePeriod.ONE_DAY) + BasicExtender("1w") >>> # Given that the main timeresolution of the static data is smaller than one day. Ex: 30 minutes >>> # The data will have a time resolution of 30 minutes, 1 day and 1 week. >>> data: List[Dict[str, TSData]] = ... >>> data += extender.extend(data)Parent
class TimePeriod (*args, **kwds)-
Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access:
Color.RED
- value lookup:
Color(1)
- name lookup:
Color['RED']
Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Parent
- enum.Enum
Class variables
var FOUR_HOURSvar ONE_DAYvar ONE_HOURvar ONE_MONTHvar ONE_WEEKvar THIRTY_MINUTES
class TimeResExtender-
Helper class that provides a standard way to create an ABC using inheritance.
Parent
- abc.ABC
Methods
def extend(self, data: List[Dict[str, TSData]], main_timestep: int = 0) ‑> List[Dict[str, TSData]]-
Extend the data with new time resolutions. By default, it uses the single_extend method to extend each timeseries data independently. However, it is possible to override this method and bypass the single_extend method to extend the data in a more complex way or to optimize the process.
Args:
data: The current data statically acquired. (Fetch from sources)
main_timestep: The index of the timeseries data in data list to use as the main series.Returns:
- The new data with the new time resolutions. (Do not mutate the original data)
def single_extend(self, data: TSData) ‑> Tuple[pandas.core.frame.DataFrame]-
Extend a single timeseries data with new time resolutions. Override this method
Args:
data: The current data statically acquired. (Fetch from sources)Returns:
- The new data with the new time resolutions. (Do not mutate the original data)
class Trade (security: str, security_price: float, amount: int, amount_borrowed: int, transaction_id: str, timestamp: datetime.datetime, trade_type: TradeType, order: TradeOrder)-
Helper class that provides a standard way to create an ABC using inheritance.
Parent
- abc.ABC
Static methods
def load(data: dict)-
This method loads a trade object from a dictionary.
Args:
data: The dictionary containing the object stateReturns:
- The object
Methods
def export(self) ‑> dict-
This method export the trade object to a JSONable dictionary.
Returns:
- The object state as a dictionary
def getCost(self) ‑> float-
This method calculates the upfront cost of the trade. It ignores the cost of borrowing the securities.
Note
It doesn't include transaction costs nor the cost of borrowing the securities.
Returns:
- The upfront cost of the trade
class TradeOrder (timestamp: datetime.datetime, security: str, security_price_limit: Tuple[Optional[float], Optional[float]], amount: int, amount_borrowed: int, trade_type: TradeType, expiry: Optional[datetime.datetime])-
Helper class that provides a standard way to create an ABC using inheritance.
Parent
- abc.ABC
Static methods
def load(data: dict)-
This method loads a trade order object from a dictionary.
Args:
data: The dictionary containing the object stateReturns:
- The object
Methods
def export(self) ‑> dict-
This method export the trade order object to a JSONable dictionary.
Returns:
- The object state as a dictionary
class TradeType (*args, **kwds)-
Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access:
Color.RED
- value lookup:
Color(1)
- name lookup:
Color['RED']
Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Parent
- enum.Enum
Class variables
var BuyLongvar BuyShortvar SellLongvar SellShort
Static methods
def available()
class Transaction (amount: float, T: TransactionType, dt: datetime.datetime, transaction_id: str = None, comment: str = None)-
Data class
Static methods
def load(data: dict)-
This method load a Transaction object from a dictionary.
Args:
data: The dictionary to load fromReturns:
- The Transaction object
Methods
def export(self) ‑> dict-
This method export the trade order object to a JSONable dictionary.
Returns:
- The object's state as a dictionary
class TransactionType (*args, **kwds)-
Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access:
Color.RED
- value lookup:
Color(1)
- name lookup:
Color['RED']
Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Parent
- enum.Enum
Class variables
var DEPOSITvar WITHDRAWAL
Static methods
def from_str(string: str)
class DividendFrequency (*args, **kwds)-
Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access:
Color.RED
- value lookup:
Color(1)
- name lookup:
Color['RED']
Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Parent
- enum.Enum
Class variables
var BIANNUALLYvar MONTHLYvar NO_DIVIDENDSvar QUARTERLYvar YEARLY
Static methods
def from_delta(days: float)def nearest(value: float, available_values: numpy.ndarray) ‑> int-
Get the nearest value in available_values. (Kinda like a custom round())
Args:
value: The value to approximate
available_values: The available values to approximate toReturns:
- The approximation (nearest value)