生活, 其他记录

使用AKShare库进行补仓回测的例子

这是之前的一篇:使用AKShare库获取股票数据。本篇使用该数据进行补仓回测,仅仅作为娱乐,以及对直观想法的验证。在代码中,AKShare 通过 Guan 软件包进行调用:https://py.guanjihuan.com

回测的主要结论是:在初始资金为 1000 元,投资时长为 6 年左右时,

  • 如果不限制补仓,跌到成本的 0.95 倍时翻倍补仓,平均利润率最大,平均加仓次数为 22 次,但平均投入资金远远超出实际,为 4.570909006502524e+26。
  • 如果限制补仓次数为 10 次,跌到成本的 0.8 倍时翻倍补仓,平均利润率最大,平均加仓次数为 5 次,平均投入资金为 242379 元。
  • 如果限制补仓次数为 4 次,跌到成本的 0.7 倍时翻倍补仓,平均利润率最大,平均加仓次数为 2~3 次,平均投入资金为 8945 元。

总结:以上结论是合理的。补仓次数的上限应该做个限制,否则投入资金越远超实际。另外,当限制的次数越小,越应该晚些补仓,给后续可能的持续下跌提供可能的拯救机会。平均加仓次数大概为限制补仓次数的一半。一般来说,第三个方案是对的,即跌到成本的 0.7 倍,也就是亏损接近 30% 时,翻倍补仓是比较科学的,这是因为在限制补仓次数为 4 次时,投入资金就已经有 2^4=16 倍的可能了,为 16000 元。

以下是具体的补仓回测 Python 代码,下载数据和运行时间可能会比较长。如果不做自定义的量化分析,可以忽略以下内容。

下载数据(大小约1G):

"""
This code is supported by the website: https://www.guanjihuan.com
The newest version of this code is on the web page: https://www.guanjihuan.com/archives/38912
"""

import guan
stock_symbols_60, stock_symbols_00, stock_symbols_30, stock_symbols_68, \
stock_symbols_8_4,stock_symbols_others = guan.stock_symbols_classification()

import os
guan.make_directory('./all_to_2024_03_07')

guan.make_directory('./all_to_2024_03_07/stock_data_60')
for stock_symbol in stock_symbols_60:
    try:
        if not os.path.exists('./all_to_2024_03_07/stock_data_60/'+stock_symbol+'.txt'):
            title, stock_data = guan.history_data_of_one_stock(symbol=stock_symbol, \
                                period='daily', start_date="19000101", end_date='21000101')
            guan.dump_data(data=stock_data, filename='./all_to_2024_03_07/stock_data_60/'+stock_symbol, file_format='.txt')
    except:
        pass
print('60下载完成')

guan.make_directory('./all_to_2024_03_07/stock_data_00')
for stock_symbol in stock_symbols_00:
    try:
        if not os.path.exists('./all_to_2024_03_07/stock_data_00/'+stock_symbol+'.txt'):
            title, stock_data = guan.history_data_of_one_stock(symbol=stock_symbol, \
                                period='daily', start_date="19000101", end_date='21000101')
            guan.dump_data(data=stock_data, filename='./all_to_2024_03_07/stock_data_00/'+stock_symbol, file_format='.txt')
    except:
        pass
print('00下载完成')

检查下载的数据是否完整:

"""
This code is supported by the website: https://www.guanjihuan.com
The newest version of this code is on the web page: https://www.guanjihuan.com/archives/38912
"""

import guan

stock_symbols_60, stock_symbols_00, stock_symbols_30, stock_symbols_68, \
stock_symbols_8_4,stock_symbols_others = guan.stock_symbols_classification()
print(len(stock_symbols_60))
print(len(stock_symbols_00))
print()

file_list_60 = guan.get_all_filenames_in_directory(directory='./all_to_2024_03_07/stock_data_60', \
                                        file_format=None, show_root_path=0, sort=1, include_subdirectory=1)
print(len(file_list_60))
file_list_00 = guan.get_all_filenames_in_directory(directory='./all_to_2024_03_07/stock_data_00', \
                                        file_format=None, show_root_path=0, sort=1, include_subdirectory=1)
print(len(file_list_00))

对数据进行预处理,只回测 2018 年之后的数据:

"""
This code is supported by the website: https://www.guanjihuan.com
The newest version of this code is on the web page: https://www.guanjihuan.com/archives/38912
"""

import guan
import numpy as np
import datetime

file_list_60 = guan.get_all_filenames_in_directory(directory='./all_to_2024_03_07/stock_data_60', \
                                        file_format=None, show_root_path=0, sort=1, include_subdirectory=1)
file_list_00 = guan.get_all_filenames_in_directory(directory='./all_to_2024_03_07/stock_data_00', \
                                        file_format=None, show_root_path=0, sort=1, include_subdirectory=1)


len_stock_60 = len(file_list_60)
guan.make_directory('./2018_01_01_to_2024_03_07/')
guan.make_directory('./2018_01_01_to_2024_03_07/stock_data_60/')
for i00 in range(len_stock_60):
    stock_data = guan.load_data('./all_to_2024_03_07/stock_data_60/'+file_list_60[i00], file_format='')
    num_data = len(stock_data)
    new_stock_data = []
    for i0 in range(num_data):
        if stock_data[i0, 0]>datetime.date(2018, 1, 1):
            new_stock_data.append(list(stock_data[i0, :]))
    new_stock_data = np.array(new_stock_data)
    guan.dump_data(data=new_stock_data, filename='./2018_01_01_to_2024_03_07/stock_data_60/'+file_list_60[i00], file_format='')

print('数据处理结束1')

len_stock_00 = len(file_list_00)
guan.make_directory('./2018_01_01_to_2024_03_07/stock_data_00/')
for i00 in range(len_stock_00):
    stock_data = guan.load_data('./all_to_2024_03_07/stock_data_00/'+file_list_00[i00], file_format='')
    num_data = len(stock_data)
    new_stock_data = []
    for i0 in range(num_data):
        if stock_data[i0, 0]>datetime.date(2018, 1, 1):
            new_stock_data.append(list(stock_data[i0, :]))
    new_stock_data = np.array(new_stock_data)
    guan.dump_data(data=new_stock_data, filename='./2018_01_01_to_2024_03_07/stock_data_00/'+file_list_00[i00], file_format='')

print('数据处理结束2')

回测策略:当跌到成本的 ratio 倍时,翻倍投入补仓。代码如下:

"""
This code is supported by the website: https://www.guanjihuan.com
The newest version of this code is on the web page: https://www.guanjihuan.com/archives/38912
"""

import guan
file_list_60 = guan.get_all_filenames_in_directory(directory='./2018_01_01_to_2024_03_07/stock_data_60', \
                                        file_format=None, show_root_path=0, sort=1, include_subdirectory=1)
file_list_00 = guan.get_all_filenames_in_directory(directory='./2018_01_01_to_2024_03_07/stock_data_00', \
                                        file_format=None, show_root_path=0, sort=1, include_subdirectory=1)
# print(len(file_list_60))
# print(len(file_list_00))
# print()

# 回测策略:当跌到成本时的 ratio 倍时,翻倍投入补仓。(这里只对00开头的股票进行回测)
buy_limit = 100
for buy_limit in [100000, 10, 4]: # 限制补仓次数
    print('限制补仓次数:', buy_limit, '\n')
    for ratio in [0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65]:
        win_count = 0
        lose_count = 0
        win_count_relative = 0
        lose_count_relative = 0
        win_count_0 = 0
        lose_count_0 = 0
        print('跌到成本的某个倍数补仓:', ratio)
        invest_money_array = []
        current_money_array = []
        buy_times_array = []
        profit_array = []
        profit_array_0 = []
        for i00 in range(len(file_list_00)):
            stock_data = guan.load_data('./2018_01_01_to_2024_03_07/stock_data_00/'+file_list_00[i00], file_format='')
            stock_data = stock_data[::-1]
            if len(stock_data) > 0:
                invest_money = 1000  # 初始投入资金
                current_money = 1000  # 当前所有资金
                buy_price = stock_data[0, 2]  # 买入的价格(第一天买入)
                cost_price = stock_data[0, 2]  # 当前持有的成本价(第一天买入)
                cost_num = invest_money/cost_price   # 当前持有的股数(为了简化,这里不做取整处理)
                len_date = len(stock_data[:, 2])
                buy_times = 0
                for i0 in range(len_date):
                    if stock_data[i0, 2]/cost_price < ratio and buy_times < buy_limit:  # 当满足策略,且补仓次数小于buy_limit时,补仓
                        current_price = stock_data[i0, 2]   # 当前的市场价
                        current_money = invest_money + (invest_money/cost_price)*current_price  # 补仓后的所有资金
                        buy_price = stock_data[i0, 2]  # 买入价为当前市场价
                        cost_num = (invest_money/cost_price)+(invest_money/buy_price)  # 更新当前持有的股数
                        cost_price = 2*invest_money/cost_num # 更新当前持有的成本价
                        invest_money = invest_money*2  # 更新总投入资金
                        buy_times += 1
                    current_price = stock_data[i0, 2]   # 当前的市场价
                    current_money = cost_num*current_price # 当前所有资金 
                buy_times_array.append(buy_times)
                invest_money_array.append(invest_money)
                current_money_array.append(current_money)
                profit_array.append(current_money/invest_money)
                profit_array_0.append(current_price/stock_data[0, 2])
                if current_money > invest_money:
                    win_count += 1
                else:
                    lose_count += 1
                if current_money/invest_money > current_price/stock_data[0, 2]:
                    win_count_relative += 1
                else:
                    lose_count_relative += 1
                if current_price > stock_data[0, 2]:
                    win_count_0 += 1
                else:
                    lose_count_0 += 1
        print('策略的平均加仓次数:', sum(buy_times_array)/len(buy_times_array))
        print('策略的平均投入资金:', sum(invest_money_array)/len(invest_money_array))
        print('策略的平均最终所有资金:', sum(invest_money_array)/len(invest_money_array))
        print('策略的平均利润率(包含本金):', sum(profit_array)/len(profit_array))
        print('完成不操作的市场平均利润率(包含本金):', sum(profit_array_0)/len(profit_array_0))
        print('策略赢的次数:', win_count)
        print('策略输的次数;', lose_count)
        print('策略相对于市场赢的次数:', win_count_relative)
        print('策略相对于市场输的次数;', lose_count_relative)
        print('完全不操作市场赢的次数:', win_count_0)
        print('完全不操作市场输的次数;', lose_count_0)
        print()
    print('-----')
    print()

代码的运行结果如下:

限制补仓次数: 100000 

跌到成本的某个倍数补仓: 0.95
策略的平均加仓次数: 22.373563218390803
策略的平均投入资金: 4.570909006502524e+26
策略的平均最终所有资金: 4.570909006502524e+26
策略的平均利润率(包含本金): 1.601242819052868
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 1527
策略输的次数; 39
策略相对于市场赢的次数: 1556
策略相对于市场输的次数; 10
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.9
策略的平均加仓次数: 13.150063856960408
策略的平均投入资金: 1.658769387179673e+17
策略的平均最终所有资金: 1.658769387179673e+17
策略的平均利润率(包含本金): 1.5531024303552605
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 1499
策略输的次数; 67
策略相对于市场赢的次数: 1549
策略相对于市场输的次数; 17
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.85
策略的平均加仓次数: 8.883141762452107
策略的平均投入资金: 15907685882056.193
策略的平均最终所有资金: 15907685882056.193
策略的平均利润率(包含本金): 1.4968591122577233
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 1432
策略输的次数; 134
策略相对于市场赢的次数: 1541
策略相对于市场输的次数; 25
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.8
策略的平均加仓次数: 6.287356321839081
策略的平均投入资金: 8395312826.309068
策略的平均最终所有资金: 8395312826.309068
策略的平均利润率(包含本金): 1.4306594407394382
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 1323
策略输的次数; 243
策略相对于市场赢的次数: 1525
策略相对于市场输的次数; 41
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.75
策略的平均加仓次数: 4.689655172413793
策略的平均投入资金: 36551542.784163475
策略的平均最终所有资金: 36551542.784163475
策略的平均利润率(包含本金): 1.3712020230242854
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 1178
策略输的次数; 388
策略相对于市场赢的次数: 1502
策略相对于市场输的次数; 64
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.7
策略的平均加仓次数: 3.5913154533844187
策略的平均投入资金: 3604818.007662835
策略的平均最终所有资金: 3604818.007662835
策略的平均利润率(包含本金): 1.3087409852952792
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 1022
策略输的次数; 544
策略相对于市场赢的次数: 1473
策略相对于市场输的次数; 93
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.65
策略的平均加仓次数: 2.7713920817369093
策略的平均投入资金: 288295.6577266922
策略的平均最终所有资金: 288295.6577266922
策略的平均利润率(包含本金): 1.249506320941488
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 890
策略输的次数; 676
策略相对于市场赢的次数: 1432
策略相对于市场输的次数; 134
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

-----

限制补仓次数: 10 

跌到成本的某个倍数补仓: 0.95
策略的平均加仓次数: 9.530012771392082
策略的平均投入资金: 934484.0357598978
策略的平均最终所有资金: 934484.0357598978
策略的平均利润率(包含本金): 1.075261266474255
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 703
策略输的次数; 863
策略相对于市场赢的次数: 1556
策略相对于市场输的次数; 10
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.9
策略的平均加仓次数: 8.529374201787995
策略的平均投入资金: 698282.8863346105
策略的平均最终所有资金: 698282.8863346105
策略的平均利润率(包含本金): 1.2608024931851716
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 996
策略输的次数; 570
策略相对于市场赢的次数: 1549
策略相对于市场输的次数; 17
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.85
策略的平均加仓次数: 7.058109833971903
策略的平均投入资金: 434781.6091954023
策略的平均最终所有资金: 434781.6091954023
策略的平均利润率(包含本金): 1.344422708133968
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 1184
策略输的次数; 382
策略相对于市场赢的次数: 1541
策略相对于市场输的次数; 25
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.8
策略的平均加仓次数: 5.560025542784164
策略的平均投入资金: 242379.3103448276
策略的平均最终所有资金: 242379.3103448276
策略的平均利润率(包含本金): 1.3564775029363771
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 1216
策略输的次数; 350
策略相对于市场赢的次数: 1525
策略相对于市场输的次数; 41
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.75
策略的平均加仓次数: 4.387611749680715
策略的平均投入资金: 136114.94252873564
策略的平均最终所有资金: 136114.94252873564
策略的平均利润率(包含本金): 1.3331222382760886
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 1144
策略输的次数; 422
策略相对于市场赢的次数: 1502
策略相对于市场输的次数; 64
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.7
策略的平均加仓次数: 3.4514687100894
策略的平均投入资金: 78360.79182630907
策略的平均最终所有资金: 78360.79182630907
策略的平均利润率(包含本金): 1.289036891287569
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 1014
策略输的次数; 552
策略相对于市场赢的次数: 1473
策略相对于市场输的次数; 93
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.65
策略的平均加仓次数: 2.7203065134099615
策略的平均投入资金: 47008.301404853126
策略的平均最终所有资金: 47008.301404853126
策略的平均利润率(包含本金): 1.2403644005900276
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 887
策略输的次数; 679
策略相对于市场赢的次数: 1432
策略相对于市场输的次数; 134
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

-----

限制补仓次数: 4 

跌到成本的某个倍数补仓: 0.95
策略的平均加仓次数: 3.9278416347381864
策略的平均投入资金: 15689.655172413793
策略的平均最终所有资金: 15689.655172413793
策略的平均利润率(包含本金): 0.857632704694966
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 435
策略输的次数; 1131
策略相对于市场赢的次数: 1556
策略相对于市场输的次数; 10
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.9
策略的平均加仓次数: 3.859514687100894
策略的平均投入资金: 15309.70625798212
策略的平均最终所有资金: 15309.70625798212
策略的平均利润率(包含本金): 0.9500671581389066
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 562
策略输的次数; 1004
策略相对于市场赢的次数: 1549
策略相对于市场输的次数; 17
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.85
策略的平均加仓次数: 3.727330779054917
策略的平均投入资金: 14551.724137931034
策略的平均最终所有资金: 14551.724137931034
策略的平均利润率(包含本金): 1.0397561151796593
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 674
策略输的次数; 892
策略相对于市场赢的次数: 1541
策略相对于市场输的次数; 25
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.8
策略的平均加仓次数: 3.4559386973180075
策略的平均投入资金: 12964.240102171138
策略的平均最终所有资金: 12964.240102171138
策略的平均利润率(包含本金): 1.1138766234110915
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 775
策略输的次数; 791
策略相对于市场赢的次数: 1525
策略相对于市场输的次数; 41
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.75
策略的平均加仓次数: 3.102171136653895
策略的平均投入资金: 11006.385696040868
策略的平均最终所有资金: 11006.385696040868
策略的平均利润率(包含本金): 1.15906081365931
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 858
策略输的次数; 708
策略相对于市场赢的次数: 1502
策略相对于市场输的次数; 64
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.7
策略的平均加仓次数: 2.6711366538952745
策略的平均投入资金: 8945.721583652617
策略的平均最终所有资金: 8945.721583652617
策略的平均利润率(包含本金): 1.1688552498829203
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 844
策略输的次数; 722
策略相对于市场赢的次数: 1473
策略相对于市场输的次数; 93
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

跌到成本的某个倍数补仓: 0.65
策略的平均加仓次数: 2.256704980842912
策略的平均投入资金: 7130.906768837804
策略的平均最终所有资金: 7130.906768837804
策略的平均利润率(包含本金): 1.1597872708009522
完成不操作的市场平均利润率(包含本金): 0.7268363188249714
策略赢的次数: 800
策略输的次数; 766
策略相对于市场赢的次数: 1432
策略相对于市场输的次数; 134
完全不操作市场赢的次数: 303
完全不操作市场输的次数; 1263

-----
207 次浏览

【说明:本站主要是个人的一些笔记和代码分享,内容可能会不定期修改。为了使全网显示的始终是最新版本,这里的文章未经同意请勿转载。引用请注明出处:https://www.guanjihuan.com

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

Captcha Code