量化交易之回测篇 - 股票回测分支(back_tester_stock_bar_branch.py)

import matplotlib.pyplot as pyplot

from math import floor

from time import sleep
from datetime import datetime

from back_tester_branch.back_tester_source_data import TQZBackTesterStockSourceData, TQZBackTesterStockConfigPath, TQZBackTesterResultPath
from public_module.tqz_extern.tools.pandas_operator.pandas_operator import pandas

from server_api.api.tqz_tushare_api import TQZTushareClient

from public_module.tqz_extern.tqz_constant import TQZStockIntervalType
from public_module.object import BarData, Exchange


class TQZBackTesterStock:
    __if300_df = pandas.read_excel(io=TQZBackTesterStockConfigPath.stock_pool_setting_path(), sheet_name='if300')
    __ic500_df = pandas.read_excel(io=TQZBackTesterStockConfigPath.stock_pool_setting_path(), sheet_name='ic500')

    @classmethod
    def start(cls):
        stock_strategy_templates = TQZBackTesterStockSourceData.load_stock_strategy_templates()

        for strategy_name, data in stock_strategy_templates.items():  # strategy templates
            for stock_name in cls.__if300_df['stock_list'].tolist():  # if300
                per_result_df = pandas.DataFrame(columns={'date', 'close_price', 'pos'})
                bars = TQZTushareClient.query_history_bars(
                    ts_symbol=stock_name,
                    exchange=Exchange(stock_name.split('.')[1]),
                    start_date=datetime.strptime(data['start_date'], '%Y-%m-%d'),
                    end_date=datetime.strptime(data['end_date'], '%Y-%m-%d'),
                    interval=TQZStockIntervalType.DAILY
                )

                strategy, single_strategy_name = None, f'{stock_name}.{strategy_name}'
                if strategy_name == 'TQZStockDoubleMaStrategy':
                    strategy = data['stock_strategy_template'](None, single_strategy_name, stock_name, {
                        "class_name": single_strategy_name,
                        "fast_window": 30,
                        "slow_window": 250,
                        "strategy_money": data['strategy_fund']
                    })
                elif strategy_name == "TQZMarcoTradingStrategy":
                    strategy = data['stock_strategy_template'](None, single_strategy_name, stock_name, {
                        "class_name": single_strategy_name,
                        "ma_window": 250,
                        "donchian_channel_window": 20,
                        "clear_position_days_window": 10,
                        "n_window": 20,
                        "strategy_money": data['strategy_fund']
                    })
                elif strategy_name in ["TQZStockRenkoScalpingStrategy", "TQZStockRenkoWaveStrategy"]:
                    strategy = data['stock_strategy_template'](None, single_strategy_name, stock_name, {
                        "class_name": single_strategy_name,
                        "fast_window": 30,
                        "slow_window": 250,
                        "strategy_money": data['strategy_fund'],
                        "renko_size": cls.__get_renko_size(bars=bars),
                        "min_tick_price_flow": data['tick_value']
                    })

                strategy.on_init()
                strategy.on_start()

                for bar in bars:
                    strategy.on_bar(bar=bar)
                    per_result_df = cls.__update_per_result_df(per_result_df=per_result_df, bar=bar, strategy=strategy)

                strategy.on_stop()
                per_result_df['net_value'] = per_result_df['balance'] / strategy.strategy_money

                strategy_name_format = single_strategy_name.replace(".", "_")
                cls.__create_netValue_png(
                    per_result_df=per_result_df,
                    strategy_name_format=strategy_name_format,
                    path=TQZBackTesterResultPath.stock_if300_fold() + f'/{strategy_name}/{strategy_name_format}.png'
                )

                sleep(1)

            for stock_name in cls.__ic500_df['stock_list'].tolist():  # ic500
                per_result_df = pandas.DataFrame(columns={'date', 'close_price', 'pos'})
                bars = TQZTushareClient.query_history_bars(
                    ts_symbol=stock_name,
                    exchange=Exchange(stock_name.split('.')[1]),
                    start_date=datetime.strptime(data['start_date'], '%Y-%m-%d'),
                    end_date=datetime.strptime(data['end_date'], '%Y-%m-%d'),
                    interval=TQZStockIntervalType.DAILY
                )

                strategy, single_strategy_name = None, f'{stock_name}.{strategy_name}'
                if strategy_name == 'TQZStockDoubleMaStrategy':
                    strategy = data['stock_strategy_template'](None, single_strategy_name, stock_name, {
                        "class_name": single_strategy_name,
                        "fast_window": 30,
                        "slow_window": 250,
                        "strategy_money": data['strategy_fund']
                    })
                elif strategy_name == "TQZMarcoTradingStrategy":
                    strategy = data['stock_strategy_template'](None, single_strategy_name, stock_name, {
                        "class_name": single_strategy_name,
                        "ma_window": 250,
                        "donchian_channel_window": 20,
                        "clear_position_days_window": 10,
                        "n_window": 20,
                        "strategy_money": data['strategy_fund']
                    })
                elif strategy_name in ["TQZStockRenkoScalpingStrategy", "TQZStockRenkoWaveStrategy"]:
                    strategy = data['stock_strategy_template'](None, single_strategy_name, stock_name, {
                        "class_name": single_strategy_name,
                        "fast_window": 30,
                        "slow_window": 250,
                        "strategy_money": data['strategy_fund'],
                        "renko_size": cls.__get_renko_size(bars=bars),
                        "min_tick_price_flow": data['tick_value']
                    })

                strategy.on_init()
                strategy.on_start()

                for bar in bars:
                    strategy.on_bar(bar=bar)
                    per_result_df = cls.__update_per_result_df(per_result_df=per_result_df, bar=bar, strategy=strategy)

                strategy.on_stop()
                per_result_df['net_value'] = per_result_df['balance'] / strategy.strategy_money

                strategy_name_format = single_strategy_name.replace(".", "_")
                cls.__create_netValue_png(
                    per_result_df=per_result_df,
                    strategy_name_format=strategy_name_format,
                    path=TQZBackTesterResultPath.stock_ic500_fold() + f'/{strategy_name}/{strategy_name_format}.png'
                )

                sleep(1)



    # --- private part ---
    @classmethod
    def __create_netValue_png(cls, per_result_df: pandas.DataFrame, strategy_name_format: str, path: str):
        pyplot.figure(figsize=(15, 10))  # size

        begin_date = per_result_df['date'].tolist()[0]
        end_date = per_result_df['date'].tolist()[-1]

        pyplot.title(f'{strategy_name_format}   {begin_date}~{end_date}')
        pyplot.gca().get_xaxis().set_visible(False)  # clear x title
        pyplot.plot(per_result_df['date'], per_result_df['net_value'], alpha=0.9)  # data
        pyplot.savefig(path)
        pyplot.close()

    @classmethod
    def __update_per_result_df(cls, per_result_df: pandas.DataFrame, bar: BarData, strategy) -> pandas.DataFrame:
        current_row = len(per_result_df)
        per_result_df.loc[current_row, 'date'] = bar.datetime
        per_result_df.loc[current_row, 'close_price'] = bar.close_price
        per_result_df.loc[current_row, 'pos'] = strategy.pos

        if current_row is 0:
            per_result_df.loc[current_row, 'cc_diff'] = 0
        else:
            per_result_df.loc[current_row, 'cc_diff'] = bar.close_price - per_result_df.loc[current_row - 1, 'close_price']

        per_result_df.loc[current_row, 'cc_pnl'] = per_result_df.loc[current_row, 'cc_diff'] * per_result_df.loc[current_row, 'pos']

        if current_row is 0:
            per_result_df.loc[current_row, 'pnl'] = 0
        elif current_row is not 0 and per_result_df.loc[current_row, 'pos'] is not 0 and per_result_df.loc[current_row - 1, 'pos'] is 0:
            per_result_df.loc[current_row, 'pnl'] = per_result_df.loc[current_row - 1, 'pnl']
        else:
            per_result_df.loc[current_row, 'pnl'] = per_result_df.loc[current_row, 'cc_pnl'] + per_result_df.loc[current_row - 1, 'pnl']

        per_result_df.loc[current_row, 'balance'] = per_result_df.loc[current_row, 'pnl'] + strategy.strategy_money

        return per_result_df

    @classmethod
    def __get_renko_size(cls, bars: list, min_tick_price_flow: float = 0.01) -> int:
        trs = []
        for bar in bars:
            hl_diff = bar.high_price - bar.low_price
            trs.append(hl_diff)

        trs.sort()

        begin_index = floor(len(trs) * 0.25)
        end_index = len(trs) - begin_index
        avg_tr = sum(trs[begin_index:end_index]) / len(trs[begin_index:end_index])

        return int((avg_tr * 0.5) / min_tick_price_flow)

if __name__ == '__main__':
    TQZBackTesterStock.start()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值