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; useget_pars()for parameters andget_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.