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.