当前位置: 首页 > 工具软件 > abu > 使用案例 >

学习abu的量化策略-修改点记录

李洋
2023-12-01

最近在学习abu的量化策略,项目地址是:https://github.com/bbfamily/abu

因为基本都是三四年前的脚本了,难免会出现很多版本不兼容的问题,今天来写一下需要修改哪些地方的代码。

首先,我也搜索到了douban上某一博主发的修改思考,地址如下:改代码,让书中的源代码能运行(量化交易之路)书评

但这次修改也在半年多前了,现在tushare接口的部分数据也在面临升级提示,故我这边按照我已有的环境和最新的(2022.03.10)tushare接口情况,进行代码修改。

tips:蜡烛图部分引用mpf的包依然还是报错,所以现在还做不了蜡烛图,如果有知道该怎么修改的小伙伴还劳烦赐教。

下面进入正文:

修改点1:

根据最新的tushare返回结果,在...\abupy\MarketBu\ABuDataParser.py新建一个解析方法:

@AbuDataParseWrap()
class JinbeiParser(object):
    """snus数据源解析类,被类装饰器AbuDataParseWrap装饰"""
    def __init__(self, symbol, df):
        """
        :param symbol: 请求的symbol str对象
        :param json_dict: 请求返回的json数据
        """
        data = df
        # 为AbuDataParseWrap准备类必须的属性序列
        if len(data) > 0:
            # 时间日期序列
            self.date = [item for item in df['trade_date']]
            # 开盘价格序列
            self.open = [item for item in df['open']]
            # 收盘价格序列
            self.close = [item for item in df['close']]
            # 最高价格序列
            self.high = [item for item in df['high']]
            # 最低价格序列
            self.low = [item for item in df['low']]
            # 成交量序列
            self.volume = [item for item in df['vol']]

在源码的...\abupy\MarketBu\ABuDataFeed.py 中,新增一个数据源,用tushare的最新的方法

并且要引用刚才新建的相关parser

from ..MarketBu.ABuDataParser import BDParser, TXParser, NTParser, SNUSParser,JinbeiParser
import tushare as ts
import datetime


class JinbeiApi(StockBaseMarket, SupportMixin):
#     """snus数据源,支持美股"""
#     K_NET_BASE = "http://stock.finance.sina.com.cn/usstock/api/json_v2.php/US_MinKService.getDailyK?" \
#                  "symbol=%s&___qn=3n"

    def __init__(self, symbol):
        """
        :param symbol: Symbol类型对象
        """
        super(JinbeiApi, self).__init__(symbol)
        # 设置数据源解析对象类
        self.data_parser_cls = JinbeiParser

    def _support_market(self):
        """声明数据源支持国内A股"""
        return [EMarketTargetType.E_MARKET_TARGET_CN]

    def kline(self,n_folds=2, start='2020-01-01', end=None):
        """日k线接口"""
#         symbol = symbol
#         print(self._symbol)
#         print(type(self._symbol))
#         print(str(self._symbol))
        symbol = str(self._symbol)
        # ts的验证码
        pro = ts.pro_api('你自己的token')
        start_dt = start
        time_temp = datetime.datetime.now() - datetime.timedelta(days=1)
        end_dt = time_temp.strftime('%Y%m%d')
        df = pro.daily(ts_code=symbol[-6:]+'.'+symbol[3:5].upper(), start_date=start_dt, end_date=end_dt)
        kl_df = self.data_parser_cls(self._symbol,df).df
        if kl_df is None:
            return None
        return StockBaseMarket._fix_kline_pd(kl_df, n_folds, start, end)

    def minute(self, n_fold=5, *args, **kwargs):
        """分钟k线接口"""
        raise NotImplementedError('JinbeiApi minute NotImplementedError!')

注意这里的token需要用你自己的token哦!

修改点2:

文件:...\abupy\MarketBu\ABuSymbolPd.py

这里是需要修改该段代码的,因为不适合我现在的Python3.8版本,其他版本根据需要修改

# 原代码
kl_pd = df.loc[benchmark.kl_pd.index]

# 修改后代码
kl_pd = df.reindex(benchmark.kl_pd.index)

修改点3:

依然是文件:...\abupy\MarketBu\ABuSymbolPd.py

需要把combine_pre_kl_pd方法中的部分代码注释掉

# 修改前
    # 获取kl_pd的起始时间
    end = ABuDateUtil.timestamp_to_str(kl_pd.index[0])
    # kl_pd的起始时间做为end参数通过make_kl_df和n_folds参数获取之前的一段时间序列
    pre_kl_pd = make_kl_df(kl_pd.name, data_mode=ABuEnv.EMarketDataSplitMode.E_DATA_SPLIT_SE, n_folds=n_folds,
                           end=end)

# 修改后
    '''修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改'''
    '''# 获取kl_pd的起始时间
    end = ABuDateUtil.timestamp_to_str(kl_pd.index[0])
    # kl_pd的起始时间做为end参数通过make_kl_df和n_folds参数获取之前的一段时间序列
    pre_kl_pd = make_kl_df(kl_pd.name, data_mode=ABuEnv.EMarketDataSplitMode.E_DATA_SPLIT_SE, n_folds=n_folds,
                           end=end)'''
    pre_kl_pd =  None
    '''修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改'''


修改点4:

在benchmark里修改!这点很重要!把benchmark的init给修改了,这样就能在run_loop_back时自由选择时间啦!

import tushare as ts
import talib
import pandas as pd
import datetime

class AbuBenchmark(PickleStateMixin):
    """基准类,混入PickleStateMixin,因为在abu.store_abu_result_tuple会进行对象本地序列化"""

    def __init__(self, benchmark=None, start=None, end=None, n_folds=2, rs=True, benchmark_kl_pd=None):
        if benchmark_kl_pd is not None and hasattr(benchmark_kl_pd, 'name'):
            """从金融时间序列直接构建"""
            self.benchmark = benchmark_kl_pd.name
            self.start = benchmark_kl_pd.iloc[0].date
            self.end = benchmark_kl_pd.iloc[-1].date
            self.n_folds = n_folds
            self.kl_pd = benchmark_kl_pd
            return

        if benchmark is None:
            if ABuEnv.g_market_target == EMarketTargetType.E_MARKET_TARGET_US:
                # 美股
                benchmark = IndexSymbol.IXIC
            elif ABuEnv.g_market_target == EMarketTargetType.E_MARKET_TARGET_HK:
                # 港股
                benchmark = IndexSymbol.HSI
            elif ABuEnv.g_market_target == EMarketTargetType.E_MARKET_TARGET_CN:
                # a股
                benchmark = IndexSymbol.SH
            elif ABuEnv.g_market_target == EMarketTargetType.E_MARKET_TARGET_FUTURES_CN:
                # 国内期货
                benchmark = IndexSymbol.BM_FUTURES_CN
            elif ABuEnv.g_market_target == EMarketTargetType.E_MARKET_TARGET_TC:
                # 币类市场
                benchmark = IndexSymbol.TC_INX
            elif ABuEnv.g_market_target == EMarketTargetType.E_MARKET_TARGET_OPTIONS_US:
                # 美股期权暂时也以IXIC做为标尺,最好是外部参数中的benchmark设置
                benchmark = IndexSymbol.IXIC
            elif ABuEnv.g_market_target == EMarketTargetType.E_MARKET_TARGET_FUTURES_GLOBAL:
                # 国际期货暂时也以BM_FUTURES_GB做为标尺
                benchmark = IndexSymbol.BM_FUTURES_GB
            else:
                raise TypeError('benchmark is None AND g_market_target ERROR!')

        self.benchmark = benchmark
        self.start = start
        self.end = end
        self.n_folds = n_folds
        '''修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改'''
        '''# 基准获取数据使用data_mode=EMarketDataSplitMode.E_DATA_SPLIT_SE,即不需要对齐其它,只需要按照时间切割
        self.kl_pd = ABuSymbolPd.make_kl_df(benchmark, data_mode=EMarketDataSplitMode.E_DATA_SPLIT_SE,
                                            n_folds=n_folds,
                                            start=start, end=end)                   '''
        self.kl_pd = ts.pro_bar(ts_code='000300.SH', asset='I',start_date = self.start,end_date=self.end)
        date_index = self.kl_pd['trade_date'].apply(
            lambda x: pd.to_datetime(x, format="%Y-%m-%d").strftime('%Y-%m-%d'))
        date_index.name = 'date'
        self.kl_pd.set_index(date_index, inplace=True)
        self.kl_pd = self.kl_pd.sort_index()
        self.kl_pd['atr21'] = talib.ATR(self.kl_pd.high, self.kl_pd.low, self.kl_pd.close, timeperiod=21)
        self.kl_pd['key'] = list(range(len(self.kl_pd)))
        tt = pd.to_datetime(self.kl_pd.index)
        self.kl_pd['date'] = tt.year * 10000 + tt.month * 100 + tt.day
        self.kl_pd.index = tt
        '''修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改修改'''
        if rs and self.kl_pd is None:
            # 如果基准时间序列都是none,就不要再向下运行了
            raise ValueError('CapitalClass init benchmark kl_pd is None')

至此,源码中没有需要修改的部分了,但是如果想完成lecture的第8个章节中的run_loop_back,依然需要配置一些代码,在执行run_loop_back之前:

# 1、不使用沙盒数据
# 使用沙盒数据,目的是和书中一样的数据环境
# abupy.env.enable_example_env_ipython()
# 使用联网数据
abupy.env.disable_example_env_ipython()


# 2、调整数据来源为JinbeiApi
# 切换数据来源为JinbeiApi
abupy.env.g_private_data_source = JinbeiApi

# 3、调整市场时间为中国A股时间
abupy.env.g_market_target = EMarketTargetType.E_MARKET_TARGET_CN

到这里,lecture的第8个回测数据源就可以用上tushare了,而且不会报错!

后面蜡烛图还没找到解决方案,依然报错,后续继续研究ing

 类似资料: