7. Custom Strategies: From Definition to Use

A custom strategy requires: tunable parameters, declared DataType inputs, a realize() implementation, then adding the instance to an Operator.

7.1. Define Tunable Parameters

Declare tunable parameters with Parameter (par_range, name, par_type, etc.) and pass pars=[...] in the strategy __init__:

from qteasy import BaseStrategy, Parameter

class MyStg(BaseStrategy):
    def __init__(self):
        super().__init__(pars=[
            Parameter('short_period', (5, 20), 10),
            Parameter('long_period', (20, 60), 30),
        ])

Then tune via set_parameter(stg_id, pars={'short_period': 8, 'long_period': 40}) in optimization or manual setup.

7.2. Declare Required Data

Declare DataType, window_length (lookback), use_latest_data_cycle, etc., so the framework prepares data before runs and realize() reads it via get_data(dtype_id).

7.3. Implement realize()

  • realize() takes no arguments; use get_pars() for parameters and get_data(dtype_id) for data.

  • Return value: Per strategy type (e.g., PT returns scalar/vector positions in 0–1; PS returns a selection list).

7.4. Add to Operator

Use add_strategy(MyStg(), run_freq=..., run_timing=...); run_freq/run_timing determine the Group.

7.5. Complete Mini Example

Below is a minimal dual moving-average timing example (logic sketch; base class and DataType per actual API):

import qteasy as qt
from qteasy import RuleIterator, Parameter

class DMA(RuleIterator):
    def __init__(self):
        super().__init__(pars=[
            Parameter('short_period', (5, 20), 10),
            Parameter('long_period', (20, 60), 30),
        ])
    def realize(self):
        close = self.get_data('close')
        p = self.get_pars()
        short = close[-p['short_period']:].mean()
        long_ = close[-p['long_period']:].mean()
        return 1.0 if short > long_ else 0.0

op = qt.Operator(signal_type='PT', run_freq='d')
op.add_strategy(DMA(), run_freq='d', run_timing='open')

More examples are in Tutorials chapters 5–7.