Module serve
Sub-modules
Classes
class Job (strategy: Strategy, data: DataPipe, lookback: datetime.timedelta, *, result_path: Optional[str] = None, params: Optional[Dict[str, Any]] = None, index_pipe: Optional[DataPipe] = None, working_directory: pathlib.PurePath = PurePosixPath('prod_data'), indicators: Union[IndicatorSet, List[IndicatorSet], Dict[int, IndicatorSet]] = IndicatorSet(n_indicators=0), trigger_cb: Optional[Callable[[StateSignals, pathlib.PurePath], None]] = None, renderer: Union[RendererList, Renderer] = None, cash_controller: CashControllerBase = <backtest.engine.cashController.CashControllerBase object>, time_res_extender: Optional[TimeResExtender] = None)-
This class is designed to run a strategy in inference mode. It is derived from the backtest class to keep as much similarity as possible. The main difference is that the Job class will not run the strategy in a loop, but will run it once and return the signals. It is designed to be used in a server environment where the strategy will be run on a schedule. (Cron schedule or with the schedule module)
Overall mechanism: The Job class receives as parameter a datapipe. When the job class is run, it starts by fetching the data from the datapipe. It then prepares the data as it is prepared in the backtest class. It then runs the strategy on the data and records the signals emitted by the strategy. It builds a StateSignals object with the signals and the state of the system (i.e. the account, the broker, the cash controller, etc.). It then calls the renderer. The renderer converts the StateSignals object into a file (or a set of files) that can be used to visualize the signals or be imported into an application. Finally, the Job class calls a trigger callback that can be used to trigger other actions such as sending a notification, buying or selling assets based on an api, etc.
How to use: The Job class is designed to be run once a backtest has been completed (To see the performance expected by the strategy). Also, there are two ways to run the Job class. The first way is to call run the run_job method once in a while (Could be scheduled with a Cron job). The second way, is to pass a schedule.Job object to the run_job method and the script will run the job at the specified interval. In that case, the script never finishes.
Example
The first example is designed to be run by a Cron job. The script will brun and exit.
>>> # imports ... >>> data_pipe = ... # A data pipe that fetches the data >>> strategy = ... # A strategy object >>> # In case a backtest has been run prior to this, we pass the path to the backtest results. This way, the >>> # Job class will load the initial parameters from the backtest results. >>> job = Job(strategy, data_pipe, timedelta(days=1), result_path="path/to/backtest/result", renderer=..., ... trigger_cb=...) >>> # In case a backtest hasn't been run, we pass the parameters directly to the Job class. >>> # The parameters are the parameters passed to the backtest class. Almost every parameters must be passed, >>> # because it doesn't have defaults. >>> job = Job(strategy, data_pipe, timedelta(days=1), params={"initial_cash": 10000, "commission": 0.01, ...}, ... renderer=..., trigger_cb=...) >>> job.run_job()The second example is designed to be run in a loop. The script will run the job every day at 5pm.
>>> # imports ... >>> data_pipe = ... # A data pipe that fetches the data >>> strategy = ... # A strategy object >>> # In case a backtest has been run prior to this, we pass the path to >>> # the backtest results. This way, the Job class will load the initial parameters from the backtest results. >>> job = Job(strategy, data_pipe, timedelta(days=1), result_path="path/to/backtest/result", renderer=..., ... trigger_cb=...) >>> # In case a backtest hasn't been run, we pass the parameters directly to the Job class. >>> # The parameters are the parameters passed to the backtest class. Almost every parameters must be passed, >>> # because it doesn't have defaults. >>> job = Job(strategy, data_pipe, timedelta(days=1), params={"initial_cash": 10000, "commission": 0.01, ...}, ... renderer=..., trigger_cb=...) >>> job.run_job(schedule.every().day.at("17:00"))Args:
strategy: The strategy to use and extract signals from.
data: The data pipeline used to fetch the data for the strategy. It must return a list of dict of TSDatawhere position in the list are different time resolutions (like in the backtest) and the keys in the dict arethe tickers.
lookback: The lookback period to fetch the data. For example, let's say the lookback is 1y, the datafetched will be from (now - 1y) to now at every run.
result_path: The path to the backtest results. If this is provided, the Job class will load theparameters from the backtest results. If this is not provided, the Job class will load the parameters from theparams dictionary.
params: The parameters to use for the backtest. If the result_path is provided, this parameter isignored. The parameters are the same as the parameters passed to the backtest class. Almost every parametersmust be passed, because it doesn't have defaults. The parameters required are: - main_timestep: The main timestep to use for the backtest. - initial_cash: The initial cash to start the backtest. - commission: The commission to apply to the trades. - relative_commission: The relative commission to apply to the trades. - margin_interest: The margin interest to apply to the trades. - min_initial_margin: The minimum initial margin to apply to the trades. - min_maintenance_margin: The minimum maintenance margin to apply to the trades. - liquidation_delay: The liquidation delay to apply to the trades. - min_initial_margin_short: The minimum initial margin for short trades. - min_maintenance_margin_short: The minimum maintenance margin for short trades. - window: The window to use for the backtest. - default_marginable: The default marginable status used in the backtest. - default_shortable: The default shortable status used in the backtest. - default_short_rate: The default short rate used in the backtest. - risk_free_rate: The risk-free rate used in the backtest. - verbose: The verbosity level of the backtest.
index_pipe: A datapipe designed to fetch the index data. This is useful to compare the strategyperformance with the index performance. It must return a list of TSData objects. Although it is recommended touse only one reference index because the renderers are designed to render only one index, it is possible toreturn more than one. It is required that the time resolution of the index is the same as the main timeresolution.
working_directory: The working directory to use to export files. This will be considered as the root bythe renderers. For example, the prebuilt renderers will export their reports in the reports directory of theworking directory.
indicators: The same indicators used for the backtest.
trigger_cb: The trigger callback to call after the renderer has rendered the StateSignals.This callback is designed to trigger other actions like sending a notification, buying or selling assets basedon an api, etc.
renderer: A renderer object designed to convert the StateSignals object to an output file. The renderercan be a single renderer or a list of renderers (RendererList). The renderers are run in the same order as theyare in the list.
cash_controller: The cash controller used during the backtest.
time_res_extender: The time resolution extender used during the backtest.Parent
Methods
def pipeline(self, now_override: Optional[datetime.datetime] = None)-
This method will run the whole pipeline. The steps of the pipeline are: 1. Fetch the data 2. Setup the Job. (Initialize the different variables) 3. Prepare the data 4. Run the cash controller 5. Run the broker (It will always be run on the previous timestep, i.e. lagging by one timestep) 6. Run the strategy 7. Save the state of the job for later warm restarts. 8. Package the signals and the state in a StateSignals object 9. Render the signals using the renderer 10. Call the trigger callback
Args:
now_override: A datetime object to override the current time. (Useful for testing in simulated environments)Returns:
- None
def run_job(self, every: Optional[ForwardRef('schedule.Job')] = None)-
This method will run the job. If the every parameter is None, the job will run once and render the signals. If the every parameter is not None, the job will run at the specified interval and never return (never exit).
Args:
every: The interval to run the job.Returns:
- None
def setup(self) ‑> Optional[datetime.datetime]-
This method will setup the backtest. It will load from cache, if it exists, the backtest state. Loading from cache the backtest state simulate a warm restart, (like the script has never stopped). If the script is runned in a cron job, so it exits after each run, and restarts at the next run, it wouldn't be able to remember the state of the job and would think it is always the first run. This is why the cache is used. It is used to remember the state of the job between runs. It is useful to remember the state to calulate the current statistics of the strategy. It will later be possible to compare the current performance with the backtest performances.
class Renderer-
This class is designed to convert a StateSignals object into a file or multiple files. The goal of exporting a StateSignals object is to be able to visualize the data in a human-readable format or to export it into a program-readable format (example: JSON, CSV, etc) for further processing. The class can be used as a decorator or derived. The derived class must implement the render method.
Example
The first example is deriving the class and implementing the render method.
>>> from backtest.serve import Renderer >>> class MyRenderer(Renderer): ... def render(self, state: StateSignals, base_path: PurePath): ... print(f"Rendering {state} to {base_path}")The second example is using the class as a decorator.
>>> from backtest.serve import Renderer >>> @Renderer() ... def my_renderer(state: StateSignals, base_path: PurePath): ... print(f"Rendering {state} to {base_path}")Parent
- abc.ABC
Methods
def render(self, state: StateSignals, base_path: pathlib.PurePath)-
Renders the state and signals and save it to a file or multiple files inside the provided base path.
Args:
state: The state and signals to render
base_path: The base path to save the rendered files
class RendererList (*renderers: Renderer)-
A class that have the same structure as a Renderer, but it contains a list of renderers. This class is used to combine multiple renderers into a single renderer. When the render method is called, it will call the render method of each renderer in the list.
Note: The order of the renderers in the list is kept.
Methods
def render(self, state: StateSignals, base_path: pathlib.PurePath)-
Run multiple renderers with the given state and base path.
Args:
state: The state and signals to render
base_path: The root path to store the rendered filesReturns:
- None
class ServerStatus (*args, **kwds)-
Used to indicate the status of the server after the strategy has been executed.
Parent
- enum.Enum
Class variables
var ERRORvar OKvar WARNING
class StateSignals (account: Account, broker: Broker, signals: Dict[str, TradeOrder], strategy: Strategy, timestamp: datetime.datetime, cash_controller: CashControllerBase, initial_cash: float, index_data: Optional[Dict[str, TSData]] = None, data: Optional[List[Dict[str, TSData]]] = None, main_idx: Optional[int] = None, backtest_params: Optional[Dict[str, Any]] = None, status: ServerStatus = Ok, exception: Optional[Exception] = None, warnings: Optional[List[warnings.WarningMessage]] = None)-
Class that stores the signals given y the strategy for the current timestep and state of the account, the broker and the portfolio. Its more of a dataclass that stores the signals and the state of the account, broker and portfolio. It also has few method for easy access to the signals.
Args:
account: The account object
broker: The broker object
signals: The signals emitted by the strategy
strategy: The strategy object
timestamp: The current timestamp (i.e. the time at which the strategy was executed)
cash_controller: The cash controller object
initial_cash: The initial cash in the account (Useful to calculate the returns in a renderer)
index_data: The index data for the current timestamp. Same time-resolution as the main time resolution.
data: The data for the current timestamp.
main_idx: The index of the main time resolution in the data list.
backtest_params: The backtest parameters passed as a dictionary.
status: The server status after the strategy has been executed.
exception: An exception object if an exception was raised during the strategy execution.
warnings: Any warning objects that were raised during the strategy execution.Instance variables
var buy_long_signals : Dict[str, TradeOrder]-
Returns the buy long signals
var buy_short_signals : Dict[str, TradeOrder]-
Returns the buy short signals
var sell_long_signals : Dict[str, TradeOrder]-
Returns the sell long signals
var sell_short_signals : Dict[str, TradeOrder]-
Returns the sell short signals
Methods
def get(self, item: str, default: Optional[Any] = None) ‑> Union[TradeOrder, Any]-
Returns the signal for the given ticker
Args:
item: The ticker to search for
default: The default value to return if no signals were emitted for the given tickerReturns:
- The TradeOrder object or the default value
class Period (*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 DAILYvar HOURLYvar MONTHLYvar QUARTERLYvar WEEKLYvar YEARLY
class StatCalculator (state: StateSignals)-
Class analog to the BacktestResults class. However, this class is used to calculate the stats in real time. It calculates the statistics based on a one-year moving window when possible. For some indicators, it is not possible because it would cause a difference in calculation of that metric between the inference and the backtest. Those metrics are marked as All-time in the comments.
Static methods
def prepare_data(state: StateSignals) ‑> (typing.List[str],) -
Extracts the relevent up-to-date data from the state object and returns it as an array.
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