量化交易之回测篇 - 股票回测数据源(back_tester_source_data)

import os
import importlib
import traceback
from datetime import datetime
from pathlib import Path

from server_api.api.tqz_tushare_api import TQZTushareClient
from tqz_strategy.template import CtaTemplate

from public_module.tqz_extern.tools.position_operator.position_operator import TQZJsonOperator
from public_module.tqz_extern.tools.file_path_operator.file_path_operator import TQZFilePathOperator
from public_module.tqz_extern.tools.pandas_operator.pandas_operator import pandas

from back_tester_core.tqz_constant import TQZBackTesterSettingType, TQZStrategyCombinationType, TQZStockPoolExcelType
from public_module.tqz_extern.tqz_constant import TQZStockIntervalType


class BackTesterDataCore:

    __back_tester_setting: dict = None

    # --- future part ---



    # --- stock part ---
    __stock_pools_df_map: dict = None
    __stock_bars_map: dict = None


    @classmethod
    def load_strategy_classes(cls, strategy_combination_type: TQZStrategyCombinationType) -> dict:
        """ """
        all_strategies_classes = cls.__get_all_strategy_classes(strategy_combination_type=strategy_combination_type)

        strategies_setting = TQZJsonOperator.tqz_load_jsonfile(
            jsonfile=cls.__strategies_setting_path(
                strategy_combination_type=strategy_combination_type
            )
        )

        _strategy_classes = {}
        for value in strategies_setting.values():
            if value["class_name"] in all_strategies_classes.keys() and value["class_name"] not in _strategy_classes.keys() and f'{value["class_name"]}.xlsx' in cls.__get_back_tester_stock_pools():
                _strategy_classes[value["class_name"]] = {
                    "strategy_class": all_strategies_classes[value["class_name"]],
                    "strategy_setting": value["setting"]
                }

        return _strategy_classes

    @classmethod
    def load_stockPoolsMap_and_barsMap(cls) -> (dict, dict):
        """ """
        if cls.__stock_pools_df_map is None:
            cls.__stock_pools_df_map = {}
            for dirpath, dirnames, filenames in os.walk(cls.__stock_pools_path()):
                for filename in filenames:
                    if filename.endswith('.xlsx') and filename in cls.__get_back_tester_stock_pools():
                        cls.__stock_pools_df_map[filename] = pandas.read_excel(f'{dirpath}/{filename}', sheet_name=TQZStockPoolExcelType.SHEET_NAME.value)

        if cls.__stock_bars_map is None:
            back_tester_setting = cls.__get_back_tester_setting(strategy_combination_type=TQZStrategyCombinationType.STOCK)

            merge_stocks = []
            for stock_pool_dataframe in cls.__stock_pools_df_map.values():
                merge_stocks += stock_pool_dataframe[TQZStockPoolExcelType.STOCKS_COLUMN.value].values.tolist()

            cls.__stock_bars_map = TQZTushareClient.query_multi_stocks_history_bars(
                stock_list=list(set(merge_stocks)),
                start=datetime.strptime(back_tester_setting[TQZBackTesterSettingType.START_DATE.value], '%Y-%m-%d'),
                end=datetime.strptime(back_tester_setting[TQZBackTesterSettingType.END_DATE.value], '%Y-%m-%d'),
                interval=cls.__get_current_interval()
            )

        return cls.__stock_pools_df_map, cls.__stock_bars_map

    @classmethod
    def get_slippage(cls, strategy_combination_type: TQZStrategyCombinationType):
        return cls.__get_back_tester_setting(
            strategy_combination_type=strategy_combination_type
        )[TQZBackTesterSettingType.SLIPPAGE.value]

    @classmethod
    def get_fee_ratio(cls, strategy_combination_type: TQZStrategyCombinationType):
        return cls.__get_back_tester_setting(
            strategy_combination_type=strategy_combination_type
        )[TQZBackTesterSettingType.FEE_RATIO.value]

    @classmethod
    def get_tick_value(cls, strategy_combination_type: TQZStrategyCombinationType):
        return cls.__get_back_tester_setting(
            strategy_combination_type=strategy_combination_type
        )[TQZBackTesterSettingType.TICK_VALUE.value]


    # --- private part ---
    @classmethod
    def __get_back_tester_stock_pools(cls):
        return cls.__get_back_tester_setting(
            strategy_combination_type=TQZStrategyCombinationType.STOCK
        )[TQZBackTesterSettingType.BACK_TESTER_STOCK_POOLS.value]

    @classmethod
    def __get_current_interval(cls) -> TQZStockIntervalType:
        interval_str = cls.__get_back_tester_setting(strategy_combination_type=TQZStrategyCombinationType.STOCK)[TQZBackTesterSettingType.INTERVAL.value]

        if interval_str in [TQZStockIntervalType.DAILY.value]:
            interval = TQZStockIntervalType.DAILY
        elif interval_str in [TQZStockIntervalType.WEEKLY.value]:
            interval = TQZStockIntervalType.WEEKLY
        elif interval_str in [TQZStockIntervalType.MONTHLY.value]:
            interval = TQZStockIntervalType.MONTHLY
        else:
            assert False, f'bad interval_str {interval_str}'

        return interval

    @classmethod
    def __get_back_tester_setting(cls, strategy_combination_type: TQZStrategyCombinationType):
        if cls.__back_tester_setting is None:
            cls.__back_tester_setting = TQZJsonOperator.tqz_load_jsonfile(
                jsonfile=cls.__back_tester_setting_path(strategy_combination_type=strategy_combination_type)
            )

        return cls.__back_tester_setting

    @classmethod
    def __get_all_strategy_classes(cls, strategy_combination_type: TQZStrategyCombinationType) -> dict:
        """ """
        root = Path(__file__).parent.parent
        stock_strategies_path = root.joinpath("tqz_strategy", f'{strategy_combination_type.STOCK.value}', "strategies")
        module_name = f'tqz_strategy.{strategy_combination_type.STOCK.value}.strategies'

        strategies_classes = {}

        for dirpath, dirnames, filenames in os.walk(stock_strategies_path):
            for filename in filenames:
                if filename.endswith(".py"):
                    strategy_module_name = ".".join(
                        [module_name, filename.replace(".py", "")])

                    try:
                        module = importlib.import_module(strategy_module_name)
                        importlib.reload(module)

                        for name in dir(module):
                            value = getattr(module, name)
                            if isinstance(value, type) and issubclass(value, CtaTemplate) and value is not CtaTemplate:
                                strategies_classes[value.__name__] = value
                    except:  # noqa
                        assert False, f"策略文件{module_name}加载失败,触发异常:\n{traceback.format_exc()}"

        return strategies_classes

    @classmethod
    def __back_tester_setting_path(cls, strategy_combination_type: TQZStrategyCombinationType) -> str:
        return TQZFilePathOperator.grandfather_path(
            source_path=TQZFilePathOperator.current_file_path(file=__file__)
        ) + f'/back_tester_config/{strategy_combination_type.value}/back_tester_setting.json'

    @classmethod
    def __strategies_setting_path(cls, strategy_combination_type: TQZStrategyCombinationType) -> str:
        return TQZFilePathOperator.grandfather_path(
            source_path=TQZFilePathOperator.current_file_path(file=__file__)
        ) + f'/back_tester_config/{strategy_combination_type.value}/strategies_setting.json'

    @classmethod
    def __stock_pools_path(cls) -> str:
        return TQZFilePathOperator.grandfather_path(
            source_path=TQZFilePathOperator.current_file_path(file=__file__)
        ) + f'/back_tester_config/stock/stock_pools'


if __name__ == '__main__':
    stock_pools_map, history_bars_map = BackTesterDataCore.load_stockPoolsMap_and_barsMap()
    strategy_classes = BackTesterDataCore.load_strategy_classes(strategy_combination_type=TQZStrategyCombinationType.STOCK)  # strategy_name strategy_classes

    print("stock_pools_map: " + str(stock_pools_map))
    print("history_bars_map: " + str(history_bars_map))
    print("strategy_classes: " + str(strategy_classes))

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值