Skip to main content

Strategies

A Strategy (src/strategies/base.py) is responsible for three things and no more:

  1. Indicatorsprocess_data(df) returns the OHLCV frame plus the columns it needs.
  2. Signalsgenerate_signals(df) maps each timestamp to a signal string.
  3. Sizing & riskcalculate_position_size, check_exit_conditions, validate_signal.

It does not fetch data, place orders, or compute portfolio metrics.

The signal vocabulary

Signals are plain strings, defined once in src/strategies/signals.py so every layer agrees:

BUY, SELL # open a position
CLOSE_BUY, CLOSE_SELL # close a position
HOLD # do nothing

Keeping them central avoids the classic bug where one layer emits "buy" and another checks for "BUY".

Lifecycle hooks

MethodWhenPurpose
calculate_required_lookback()constructionbars needed before indicators are valid
initialize()start of a runvalidate parameters / relationships
process_data(df)each batch/baradd indicator columns
generate_signals(df)after processingproduce {timestamp: signal}
process_real_time_data(...)live, per barfold a streamed bar into a rolling buffer and emit the latest signal

Position sizing

calculate_position_size(capital, price) derives a size from risk_per_trade and stop_loss, then clamps it to the configured limits (max_position_size, max_total_risk). It is the smallest of the three constraints — risk target, per- position notional cap, and total-risk cap.

Parameters & validation

Each strategy declares PARAM_RANGES with min/max/step/default/type. The base class coerces and range-checks every supplied value at construction, so an out-of-range parameter fails fast. step also lets the optimizer search the space.

The bundled strategy: volume_spike

VolumeSpikeStrategy enters in the direction of a short/long EMA trend when a volume spike confirms a move out of an RSI extreme, using only the pure indicators. See Extending to add your own.