[Day 20] 回测与报表

一、说明

老样子,又到了喜闻乐见的程序整理环节,我们今天会完成下列事项

  • 资料拆分:以1:1比例分成训练集与验证集。
  • 报表显示:包括年化报酬率、最大跌幅等日後分析与视觉化时需要的资料。
  • 参数优化

训练器

主要作用为策略回测,策略参数优化,回测完毕後回传该股票的获利与风险报表。

def bt_trainer(stock_index, test_strategy, opt=False, opt_params=None):
    print(stock_index)

    train_df = load_stock(stock_index, start_year=2012, end_year=2015)
    if len(train_df) == 0:
        return pd.DataFrame()

    valid_df = load_stock(stock_index, start_year=2016, end_year=2019)
    if len(valid_df) == 0:
        return pd.DataFrame()

    train_holding_cash = (
        1000
        * train_df.groupby(pd.DatetimeIndex(train_df.index).to_period("M"))
        .nth(0)["Close"]
        .sum()
    )

    valid_holding_cash = (
        1000
        * valid_df.groupby(pd.DatetimeIndex(valid_df.index).to_period("M"))
        .nth(0)["Close"]
        .sum()
    )

    train_bt = Backtest(
        train_df,
        test_strategy,
        cash=train_holding_cash,
        commission=0.004,
        # exclusive_orders=True,
        trade_on_close=True,
    )

    valid_bt = Backtest(
        valid_df,
        test_strategy,
        cash=valid_holding_cash,
        commission=0.004,
        # exclusive_orders=True,
        trade_on_close=True,
    )

    if opt:
        train_result = train_bt.optimize(**opt_params)

        valid_result = valid_bt.run(**train_result["_strategy"].params)
    else:
        train_result = train_bt.run()
        valid_result = valid_bt.run()

    result = train_result.copy()
    result["stock_id"] = stock_index
    result["Strategy"] = test_strategy.__name__
    result["Params"] = result["_strategy"].params
    result["Train Return (Ann.) [%]"] = train_result["Return (Ann.) [%]"]
    result["Train Max. Drawdown [%]"] = train_result["Max. Drawdown [%]"]
    result["Train Sharpe Ratio"] = train_result["Sharpe Ratio"]
    result["Train SQN"] = train_result["SQN"]
    result["Valid Return (Ann.) [%]"] = valid_result["Return (Ann.) [%]"]
    result["Valid Max. Drawdown [%]"] = valid_result["Max. Drawdown [%]"]
    result["Valid Sharpe Ratio"] = valid_result["Sharpe Ratio"]
    result["Valid SQN"] = valid_result["SQN"]
    # result["Backtest Train"] = train_bt
    # result["Backtest Valid"] = valid_bt

    opt_str = "opt" if opt else "std"
    plot_dir = f"./data/Strategy/{test_strategy.__name__}/{opt_str}"
    Path(plot_dir).mkdir(parents=True, exist_ok=True)
    valid_bt.plot(
        filename=plot_dir + f"/{stock_index}.html",
        open_browser=False,
    )

    df = result.to_frame().transpose()

    return df

报表整理

def report_generate(frames, test_strategy, opt):
    final_df = pd.concat(frames).reset_index(drop=True)

    final_df = final_df.loc[
        final_df["Duration"] == final_df["Duration"].max()
    ].reset_index(drop=True)

    stock_name = pd.read_csv(
        "data/stock_id.csv", dtype={"stock_id": str, "stock_name": str}
    )

    profit_df = final_df.merge(stock_name, on="stock_id")

    report_df = profit_df[
        [
            "stock_id",
            "stock_name",
            "Train Return (Ann.) [%]",
            "Train Max. Drawdown [%]",
            "Train Sharpe Ratio",
            "Train SQN",
            "Valid Return (Ann.) [%]",
            "Valid Max. Drawdown [%]",
            "Valid Sharpe Ratio",
            "Valid SQN",
        ]
    ]

    opt_str = "opt" if opt else "std"

    report_dir = f"./data/Strategy/{test_strategy.__name__}/{opt_str}"
    Path(report_dir).mkdir(parents=True, exist_ok=True)

    report_df.to_csv(
        report_dir + "/Report.csv",
        index=False,
        header=True,
    )

    report_df = pd.read_csv(report_dir + "/Report.csv", dtype={"stock_id": str})

    return report_df

二、结语

回测的部分差不多结束了,明天会测试几个常见的几种策略。


<<:  [DAY 10] Pytorch 简介

>>:  【Day 10】- 藏起来的 Process 真的看不见摸不着?(讲解找出断链後的 Process 方法)

常用工具介绍(1)-postman、ngrok

今天先来介绍我们之後会使用到的工具, 在本地开发的困扰就是, 别人的机器、服务器连不到你, 这时候n...

2021 年 iOS 应用程序开发七种最佳语言

移动应用程序现在几乎是每个在线业务的必备品。最新的 StatCounter 数据显示,多达56% 的...

【图解演算法教学】还在用古老的二元搜寻法?是时候跟上「Hash Search」的车尾灯了!

Youtube连结:https://bit.ly/2Uv2sBf 在我们还没学资料结构前,通常都用...

[Day27] 透过GCP实作(3/4):建立RealTime Database即时读入/存取资料

从昨天所提及的架构,让你在爬虫获取资料的情境下使Cloud Function能各司所职。 并使维护...

git不再支援帐号密码验证

git在8/12停止了使用帐号密码作为资料上传的验证,改为较为安全的ssh,所以假如你使用帐号密码作...