Core Class Definitions
base_class.Strategy
The Strategy class is the highest level abstract class that stores all of the details of a Surmount trading strategy.
It is not passed any inputs on instantiation, but the concrete implementation overload to do so.
interval
abstractmethod
property
assets
abstractmethod
property
data
property
run(data)
abstractmethod
Runs the core logic of the strategy and returns a TargetAllocation object.
:param data: a dictionary identifiying OHLCV and alternative data.
base_class.TargetAllocation
The TargetAllocation class is a simple class that allows strategy output to be checked for validity and consistent across all strategies.
:param target_allocation: a dictionary mapping string tickers to float portfolio allocations (sum must be <= 1)
__init__(target_allocation)
Persistent strategy state
A strategy process is long lived, but it is rebuilt from __init__ on every
restart: a deploy, a watchdog relaunch, a host reboot, a manual code apply.
Anything kept on self is lost unless the strategy declares it.
class TradingStrategy(Strategy):
persistent_attrs = ["active_positions", "exited_tickers"]
memory_version = 1 # optional; defaults to 1
def __init__(self):
self.active_positions = {} # restored from the last saved snapshot
self.exited_tickers = [] # restored from the last saved snapshot
self.stop_loss_pct = 0.12 # NOT declared, so always read from code
Declared state is NOT reset by a restart. Restarting a strategy used to be
a clean slate; for the declared names it no longer is. After a restart
active_positions above holds whatever the strategy last saved, not {}.
Anything that should follow an edit to the code -- thresholds, universes,
tuning constants -- must stay undeclared, so it is read from __init__ every
time.
What can be declared
Only the names listed in persistent_attrs are saved and restored. Their
values must be built from:
dict (string keys only), list, str, int, float, bool, None, and
any nesting of those. NumPy scalars are converted to plain Python numbers.
Anything else -- a set, a tuple, a DataFrame, a datetime, an arbitrary
object -- is rejected, not converted. A set silently coming back as a
list after a restart would change the strategy's own logic, which is worse
than not saving it. A backtest raises on an unsupported value so the
problem shows up before the strategy goes live; live trading logs and alerts,
keeps the in-process value, and keeps trading.
Store a set as a sorted list, a tuple as a list, and a timestamp as an
ISO-8601 str, converting back in run().
Version
memory_version is optional and defaults to 1. Bump it to start from a clean
slate: when the stored snapshot's version differs from the class's, the stored
state is discarded and the strategy starts from its __init__ values. Editing
the strategy's code does not clear state on its own -- only an explicit
version bump does.
Backtests
Declared attributes are ordinary in-process values in a backtest. Nothing is
read from or written to the live state store, and every backtest starts from
the __init__ values.