策略实现#
示例策略#
通常情况下,策略会有多个指标,且之间有较复杂的依赖关系,此时TradePy会通过指标函数的参数声明,推断出正确的指标计算顺序。因而,使用TradePy时,您只需关注指每个标计如何计算和以及判断买卖信号。
提示
该示例代码可在 快速上手 教程中找到。
单函数,多指标#
如果您的策略有很多计算方式雷同的指标(比如均线),那么每个均线指标单独写一个计算方法,或许显得有些冗余。TradePy提供了一种更简洁的写法,可以用单个函数计算多个指标。借此可以简化上述的实现:
class MovingAverageCrossoverStrategy(BacktestStrategy):
# outputs: 输出指标的名称
@tag(outputs=["ma10", "ma30", "ma120"], notna=True)
def moving_averages(self, close):
# 逐个返回指标结果,注意顺序要和outputs对应
return talib.EMA(close, 10), talib.SMA(close, 30), talib.SMA(close, 120)
@tag(outputs=["ma10_ref1", "ma30_ref1"], notna=True)
def moving_averages_ref1(self, ma10, ma30) -> pd.Series:
return ma10.shift(1), ma30.shift(1)
def should_buy(self, sma120, ema10, sma30,
ema10_ref1, sma30_ref1, close, company) -> BuyOption | None:
if "ST" not in company:
if (ema10 > sma120) and (ema10_ref1 < sma30_ref1) and (ema10 > sma30):
return close, 1
def should_sell(self, ema10, sma30, ema10_ref1, sma30_ref1):
return (ema10_ref1 > sma30_ref1) and (ema10 < sma30)
def pre_process(self, df: pd.DataFrame) -> pd.DataFrame:
return df.query('market != "科创板"').copy()
内置指标#
5均、10均、20均、MACD之类的常用指标,也没有必要每个策略中都重复实现一遍。让策略类继承 FactorsMixin
,则可直接开始使用各类常用指标,具体可用指标请查阅 FactorsMixin 的实现。
现在,我们可以进一步简化策略的实现,只留下”前一日指标”部分的计算方法:
from tradepy.strategy.factors import FactorsMixin
class MovingAverageCrossoverStrategy(BacktestStrategy, FactorsMixin):
@tag(outputs=["ema10_ref1", "sma30_ref1"], notna=True)
def moving_averages_ref1(self, ema10, sma30) -> pd.Series:
return ema10.shift(1), sma30.shift(1)
def should_buy(self, sma120, ema10, sma30,
ema10_ref1, sma30_ref1, close, company) -> BuyOption | None:
if "ST" not in company:
if (ema10 > sma120) and (ema10_ref1 < sma30_ref1) and (ema10 > sma30):
return close, 1
def should_sell(self, ema10, sma30, ema10_ref1, sma30_ref1):
return (ema10_ref1 > sma30_ref1) and (ema10 < sma30)
def pre_process(self, df: pd.DataFrame) -> pd.DataFrame:
return df.query('market != "科创板"').copy()
可调参数#
在开发策略时,一般无法最初就确定最佳的参数组合(比如均线类型、RSI周期、布林带周期、止损止盈点位),而需要反复回测以找到预期收益最大的一组参数。
TradePy支持通过 StrategyConf.custom_params
提供自定义参数,即可在策略类中直接在 self
上访问参数值。继续用同样的例子,我们可以再加一个策略逻辑“只买入股价在某个最低值以上的股票”:
提示
请参考”寻参优化”教程
from tradepy.strategy.factors import FactorsMixin
from tradepy.core.conf import BacktestConf, StrategyConf
class MovingAverageCrossoverStrategy(BacktestStrategy, FactorsMixin):
# 其他不变 ...
def should_buy(self, sma120, ema10, sma30, orig_open,
ema10_ref1, sma30_ref1, close, company) -> BuyOption | None:
if "ST" not in company:
# `orig_open`由TradePy提供,是未复权前的实际开盘价
if orig_open >= self.min_stock_price:
if (ema10 > sma120) and (ema10_ref1 < sma30_ref1) and (ema10 > sma30):
return close, 1
conf = BacktestConf(
cash_amount=1e5,
strategy=StrategyConf(
stop_loss=4.5,
take_profit=3,
custom_params={
# 自定义参数在这里
"min_stock_price": 5
}
)
)
MovingAverageCrossoverStrategy.backtest(df, conf)
API#
- class tradepy.strategy.factors.FactorsMixin#
- atr(high, low, close)#
平均真实价格波动
atr_period: 均值周期,默认14
- boll(close)#
布林带, 自定义参数:
boll_period: 均值周期, 默认20
boll_dev_up: 上轨标准差, 默认2
boll_dev_down: 下轨标准差, 默认2
输出指标: boll_lower, boll_middle, boll_upper
- ema10(close: Series)#
指数移动10均
- ema120(close: Series)#
指数移动120均
- ema20(close: Series)#
指数移动20均
- ema250(close: Series)#
指数移动250均
- ema30(close: Series)#
指数移动30均
- ema5(close: Series)#
指数移动5均
- ema60(close: Series)#
指数移动60均
- macd(close: Series)#
MACD指标
- rsi(close)#
RSI, 自定义参数:
rsi_fast_period: 快周期, 默认6
rsi_mid_period: 中周期, 默认12
rsi_slow_period: 慢周期, 默认24
输出指标: rsi_fast, rsi_mid, rsi_slow
- skdj(close: Series, low: Series, high: Series)#
SKDJ - 慢速随机指标
输出指标: sdj_k, sdj_d
- sma10(close: Series)#
简单移动10均
- sma120(close: Series)#
简单移动120均
- sma20(close: Series)#
简单移动20均
- sma250(close: Series)#
简单移动250均
- sma30(close: Series)#
简单移动30均
- sma5(close: Series)#
简单移动5均
- sma60(close: Series)#
简单移动60均
- typical_price(high, low, close)#
典型价格 = (high + low + close) / 3