从零开始搭建一个量化交易系统

贵客云 2022-11-20 11:12 阅读 14

本期将从零开始,手动搭建一个基于规则的简单量化交易系统,旨在提高对整个过程的理解能力。

Step 1: 数据加载

其中股票数据采用已存好的CSV数据,数据的获取方式可参见

另外采用 TA-lib 的 RSI 技术指标构建买入卖出信号,详情可参见

# Step 1: load dataset and generate features
def prepare_data(codes=['000300.SH', '399006.SZ'], start_time="20100101", end_time="20211231"):
    df = load_data(codes, start_time, end_time)

    df["rsi"] = ta.RSI(df.close, timeperiod=14)
    df["to_buy"] = ""
    df.loc[df["rsi"] <= 30, 'to_buy'] = True
    df['to_buy'] = df['to_buy'].astype('bool')

    df["to_sell"] = ""
    df.loc[df["rsi"] >= 70, 'to_sell'] = True
    df['to_sell'] = df['to_sell'].astype('bool')
    return df

Step 2: 指定策略

策略规则非常简单:

  • 账户初始值100000,每只股票占相同比重
  • 根据数据的买入信号买入,卖出信号卖出
# Step 2: prepare strategy
class SelectBySignal(object):
    def __init__(self, signal_buy='to_buy', signal_sell='to_sell'):
        super(SelectBySignal, self).__init__()
        self.signal_buy = signal_buy
        self.signal_sell = signal_sell

    def __call__(self, context):
        bar = context['bar'].copy()

        acc = context['acc']
        holding = acc.get_holding_instruments()

        to_buy = list(bar[bar[self.signal_buy]].index)
        to_sell = list(bar[bar[self.signal_sell]].index)

        instruments = to_buy + holding
        to_selected = []
        for s in instruments:
            if s not in to_sell:
                to_selected.append(s)
        context['selected'] = to_selected

        n = len(to_selected)
        if n > 0:
            context['weights'] = {code:1/n for code in to_selected}
        else:
            context['weights'] = {}
        return False

class Strategy:
    def __init__(self, algo=None):
        self.algo = algo
        self.acc = Account()

    def algo_processor(self, context):
        if self.algo(context) is True: #如果algo返回True,直接不运行,本次不调仓
            return None
        return context['weights']

    def onbar(self, index, date, df_bar):
        self.acc.update_bar(date, df_bar)
        weights = self.algo_processor({'index': index, 'bar':df_bar, 'date':date, 'acc':self.acc})
        if weights is not None:
            self.acc.adjust_weights(date, weights)

Step 3: 回测

根据上述数据和策略进行回测

# Step 3: backtest
class Backtest:
    def __init__(self, df):
        self.df = df
        self.dates = self.df.index.unique()
        self.observers = []

    def onbar(self, index, date):
        df_bar = self.df.loc[date]
        if type(df_bar) is pd.Series:
            df_bar = df_bar.to_frame().T

        df_bar.index = df_bar['code']
        self.strategy.onbar(index, date, df_bar)

    def run(self, s):
        self.strategy = s
        for index, date in enumerate(self.dates):
            self.onbar(index, date)
        return self.get_results()

    def get_results(self):
        s = self.strategy
        df = s.acc.get_results_df()
        return df

Step 4: 分析

分析该策略的表现,并与沪深300指数进行对比

# Step 4: analysis
def analysis(start, end, benchmarks=[]):
    equities = []
    for benchmark in benchmarks:
        bench_df = load_from_file(benchmark)[start:end]
        se = (bench_df['rate'] + 1).cumprod()
        se.name = benchmark
        equities.append(se)

    path = os.path.dirname(__file__)
    filename = os.path.dirname(path)+'/results/first_test.csv'
    if os.path.exists(filename):
        df = pd.read_csv(filename)
        df['date'] = df['date'].apply(lambda x: str(x))
        df.index = df['date']
        se = (df['rate'] + 1).cumprod()
        se.name = 'strategy'
        equities.append(se)

    df_equities = pd.concat(equities, axis=1)
    df_equities.dropna(inplace=True)
    print(df_equities)

    from performance import PerformanceUtils

    df_ratios, df_corr, df_years = PerformanceUtils().calc_equity(df_equity=df_equities)
    return df_equities, df_ratios, df_corr, df_years

运行主函数

if __name__ == '__main__':
    date_start = "20100101"
    date_end = "20211231"
    df = prepare_data(codes=['000300.SH', '399006.SZ'], start_time=date_start, end_time=date_end)

    algo = SelectBySignal(signal_buy='to_buy', signal_sell='to_sell')
    s = Strategy(algo=algo)

    b = Backtest(df=df)
    df = b.run(s)

    path = os.path.dirname(__file__)
    df.to_csv(os.path.dirname(path) + '/results/first_test.csv')

    df_equities, df_ratios, df_corr, df_years = analysis(start=date_start, end=date_end, benchmarks=['000300.SH'])
    display(df_ratios)

    fig = plt.figure(figsize=(8, 6))
    ax1 = fig.add_subplot(2, 1, 1)
    ax2 = fig.add_subplot(2, 1, 2)
    df_equities.plot(ax=ax1)
    if df_years is not None:
        print(df_years)
        df_years.T.plot(kind='bar', ax=ax2, use_index=True)
    plt.show()

得到结果如下:

分别为累积的各项数据对比,以及各年的年化对比

  • 累计收益

\begin{equation} \begin{gathered} \text { Total Returns }=\left(P_{\text {end }}-P_{\text {start }}\right) / P_{\text {start }} * 100 \% \end{gathered} \end{equation}

\begin{equation} P_{\text {end }} \end{equation} :策略最终股票和现金的总价值

P_{\text {start }} :策略开始股票和现金的总价值

  • 年化收益

\text { Total Annualized Returns }=R_{p}=\left((1+P)^{\frac{250}{n}}-1\right) * 100 \%

P :策略收益

n :策略执行天数

  • 波动率(Algorithm Volatility)

用来测量策略的风险性,波动越大代表策略风险越高

\text { Algorithm Volatility }=\sigma_{p}=\sqrt{\frac{250}{n-1} \sum_{i=1}^{n}\left(r_{p}-\overline{r_{p}}\right)^{2}}

r_{p} :策略每日收益率

\overline{r_{p}}=\frac{1}{n} \sum_{i=1}^{n} r_{p i} :策略每日收益率的平均值

  • 夏普比率

表示每承受一单位总风险,会产生多少的超额报酬,可以同时对策略的收益与风险进行综合考虑。

\text { Sharpe Ratio }=\frac{R_{p}-R_{f}}{\sigma_{p}}

R_{p} :策略年化收益率

R_{f} :无风险利率(默认0.04)

\sigma_{p} :策略收益波动率

            累计收益   年化收益    波动率    夏普比   最大回撤  年化收益与最大回撤比
000300.SH  0.413      0.030     0.228     0.132   -0.467       0.064
strategy   1.241      0.073     0.248     0.294   -0.576       0.127

            2010   2011   2012   2013   2014  ...   2017   2018   2019   2020   2021
000300.SH -0.117 -0.265  0.098 -0.077  0.522  ...  0.206 -0.263  0.380  0.255 -0.044
strategy  -0.051 -0.316  0.057  0.319  0.305  ...  0.040 -0.276  0.424  0.430  0.044

做成图如下所示:

完整代码参见

另外也可参考:

分类: 财经/投资理财 关键词: 量化交易
原文 编辑 投诉 置顶 分享
推荐
快讯
剧透网 展会网 乡村游
营销软件 行业信息


营销 网络营销 自媒体营销 产品推广 营销策划 媒体投放 电商营销 广告联盟 科技 大数据 人工智能 智能硬件 工业互联网 物联网
财经 跨境电商 投资理财 量化交易 价值投资 招商加盟 食品招商 餐饮加盟