[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[原创代码] [Python]北上资金持仓市值排序跟踪策略

本帖最后由 老刘1号 于 2023-3-3 12:32 编辑

论坛正好有python板块,发来玩玩
回测环境:聚宽量化
  1. import talib
  2. from prettytable import PrettyTable
  3. import pandas
  4. import datetime
  5. import time
  6. from jqdata import *
  7. def initialize(context):
  8.     # 初始化变量
  9.     g.buy_stock_count = 20
  10.     # 设定基准为沪深300
  11.     set_benchmark('000300.XSHG')
  12.     # True为开启动态复权模式,使用真实价格交易
  13.     set_option('use_real_price', True)
  14.     # 设定避免未来函数模式
  15.     set_option("avoid_future_data", True)
  16.     # 股票类交易手续费和滑点
  17.     set_order_cost(
  18.         OrderCost(
  19.         open_tax        =0,
  20.         close_tax       =0.001,
  21.         open_commission =0.0003,
  22.         close_commission=0.0003,
  23.         min_commission  =5),
  24.         type            ='stock')
  25.     set_slippage(FixedSlippage(0.02))
  26.     # 设置日志级别
  27.     log.set_level('order', 'error')
  28.     # 每天运行
  29.     run_daily(daily,'open')
  30. def daily(context):
  31.     adjust_position(context, select_stocks(context))
  32.         
  33. def select_stocks(context):
  34.     #沪深股通持仓
  35.     df=finance.run_query(
  36.         query(finance.STK_HK_HOLD_INFO)\
  37.         .filter(finance.STK_HK_HOLD_INFO.day>=context.previous_date)\
  38.         .filter(finance.STK_HK_HOLD_INFO.link_id.in_([310001,310002])))
  39.     stocks = [ {
  40.             'code' : code,
  41.             'name' : name,
  42.             'number' : share_number,
  43.             'price' : price,
  44.             'value' : share_number * price
  45.         } for code, name, share_number, price in zip(
  46.         list(df.code), \
  47.         list(df.name), \
  48.         list(df.share_number), \
  49.         list(get_price(
  50.             security=list(df.code),
  51.             panel=False,
  52.             start_date=context.previous_date,
  53.             end_date=context.previous_date,
  54.             frequency='daily',
  55.             fields='close',
  56.             skip_paused=False,
  57.             fq='pre')['close'])
  58.     )]
  59.     #按持仓市值排序
  60.     stocks = sorted(stocks, key = lambda stock: stock['value'], reverse=True)
  61.     #for stock in filter((lambda x: x['price'] < 200), stocks[:40]):
  62.         #print("{} {} {} {}".format(stock['code'], stock['name'], stock['value'], stock['price']))
  63.     #print([i['code'] for i in filter((lambda x: x['price'] < 200), stocks[:40])])
  64.     return [stock['code'] for stock in stocks][:g.buy_stock_count]
  65.         
  66. def filter_paused_and_st_stock(stock_list):
  67.     current_data = get_current_data()
  68.     return [stock for stock in stock_list if not current_data[stock].paused
  69.     and not current_data[stock].is_st and 'ST' not in current_data[stock].
  70.     name and '*' not in current_data[stock].name and '退' not in current_data[stock].name]
  71.    
  72. def adjust_position(context, buy_stocks):
  73.     # 现持仓的股票,如果不在“目标池”中,且未涨停,就卖出
  74.     if len(context.portfolio.positions)>0:
  75.         last_prices = history(1, '1m', 'close', security_list=list(context.portfolio.positions.keys()))
  76.         for stock in list(context.portfolio.positions.keys()):
  77.             if stock not in buy_stocks :
  78.                 curr_data = get_current_data()
  79.                 if last_prices[stock][-1] < curr_data[stock].high_limit:
  80.                     order_target_value(stock, 0)
  81.     # 依次买入“目标池”中的股票            
  82.     for stock in buy_stocks:
  83.         position_count = len(context.portfolio.positions)
  84.         if g.buy_stock_count > position_count:
  85.             value = context.portfolio.cash / (g.buy_stock_count - position_count)
  86.             if context.portfolio.positions[stock].total_amount == 0:
  87.                 stock_price = get_price(
  88.                     security=stock,
  89.                     panel=False,
  90.                     start_date=context.previous_date,
  91.                     end_date=context.previous_date,
  92.                     frequency='daily',
  93.                     fields='close',
  94.                     skip_paused=False,
  95.                     fq='pre')['close']
  96.                 order(stock, (((context.portfolio.available_cash+context.portfolio.positions_value+ context.portfolio.returns)/g.buy_stock_count)/stock_price)//100*100)
  97.                
  98. def show_stock(stock):
  99.     '''
  100.     获取股票代码的显示信息   
  101.     :param stock: 股票代码,例如: '603822.SH'
  102.     :return: str,例如:'603822 嘉澳环保'
  103.     '''
  104.     return "%s %s" % (stock[:6], get_security_info(stock).display_name)
  105.    
  106. def get_portfolio_info_text(context,new_stocks,op_sfs=[0]):
  107.     # new_stocks是需要持仓的股票列表
  108.     sub_str = ''
  109.     table = PrettyTable(["仓号","股票", "持仓", "当前价", "盈亏率","持仓比"])  
  110.     for sf_id in range(len(context.subportfolios)):
  111.         cash = context.subportfolios[sf_id].cash
  112.         p_value = context.subportfolios[sf_id].positions_value
  113.         total_values = p_value +cash
  114.         if sf_id in op_sfs:
  115.             sf_id_str = str(sf_id) + ' *'
  116.         else:
  117.             sf_id_str = str(sf_id)
  118.         for stock in list(context.subportfolios[sf_id].long_positions.keys()):
  119.             position = context.subportfolios[sf_id].long_positions[stock]
  120.             if sf_id in op_sfs and stock in new_stocks:
  121.                 stock_str = show_stock(stock) + ' *'
  122.             else:
  123.                 stock_str = show_stock(stock)
  124.             stock_raite = (position.total_amount * position.price) / total_values * 100
  125.             table.add_row([sf_id_str,
  126.                 stock_str,
  127.                 position.total_amount,
  128.                 position.price,
  129.                 "%.2f%%"%((position.price - position.avg_cost) / position.avg_cost * 100),
  130.                 "%.2f%%"%(stock_raite)]
  131.                 )
  132.         if sf_id < len(context.subportfolios) - 1:
  133.             table.add_row(['----','---------------','-----','----','-----','-----'])
  134.         sub_str += '[仓号: %d] [总值:%d] [持股数:%d] [仓位:%.2f%%] \n'%(sf_id, total_values,
  135.             len(context.subportfolios[sf_id].long_positions), p_value*100/(cash+p_value))
  136.     log.info('持仓详情:\n' + sub_str + str(table))
复制代码
回测数据
  1. 回测时间
  2. 2022-02-08 20:20:53
  3. 回测区间
  4. 2017-03-20 - 2022-02-07
  5. 策略收益
  6. 129.20%
  7. 策略年化收益
  8. 19.07%
  9. 超额收益
  10. 70.43%
  11. 基准收益
  12. 34.48%
  13. 阿尔法
  14. 0.128
  15. 贝塔
  16. 0.915
  17. 夏普比率
  18. 0.759
  19. 胜率
  20. 0.846
  21. 盈亏比
  22. 13.917
  23. 最大回撤
  24. 28.29%
  25. 索提诺比率
  26. 1.082
  27. 日均超额收益
  28. 0.05%
  29. 超额收益最大回撤
  30. 13.77%
  31. 超额收益夏普比率
  32. 0.857
  33. 日胜率
  34. 0.536
  35. 盈利次数
  36. 11
  37. 亏损次数
  38. 2
  39. 信息比率
  40. 1.376
  41. 策略波动率
  42. 0.199
  43. 基准波动率
  44. 0.193
  45. 最大回撤区间
  46. 2021/02/10,2022/01/28
复制代码
1

评分人数

本帖最后由 523066680 于 2023-3-2 23:23 编辑

好多名词还没弄明白,为什么有些用了未来函数的指标看起来很准?
为什么很多人在指标市场里明确不要带未来函数的指标?

TOP

本帖最后由 老刘1号 于 2023-3-3 00:06 编辑

回复 2# 523066680


    未来函数就是在当时那个时间点获取不了的数据,比如说在早盘的时候获得当天的晚间新闻
有的时候未来函数也会比较隐蔽,比如说我写一个策略,在12年全仓茅台,然后获得了很不错的收益,
虽然看似在程序中没有用到任何未来函数,但是其实我知道茅台会涨(这是一个后验的指标,当时肯定不知道),所以这也算一种未来函数
只要量化模型内用了未来函数,可以说模型就是完全无效的

其实量化交易用历史数据训练模型本身也有很大的问题,它的大假设就是历史会机械重复,实际上不一定
而且某种程度上来说,量化模型不触及商业的本质,很多投资大师都是靠实地调研获取一些“不能量化”的数据,
从经济学的角度来说,信息不对称才能赚钱,网上数据都是公开的,大家信息差很小,训练的模型都差不多,那么可操作的空间就很小
所以我后面也没再深入研究了

当然高频量化(做市商)和手动交易转机器交易还是有意义的,
不过前面的已经很卷了,都是大佬用自己做的FPGA,放到离交易所很近的机房里面,进行微秒级别的交易
后边的话,就是如果有固定的策略,而且懒得手动操作的话,可以写成程序帮忙交易
我发的python代码其实就属于第二种,不过我觉得还是直接买几个量化基金和历史业绩优秀的主动基金比较好,所以没有实盘
1

评分人数

    • 523066680: 感谢分享,少走很多弯路PB + 18

TOP

回复 2# 523066680


    推荐一篇文:
https://blog.csdn.net/weixin_42219751/article/details/102658975

TOP

不怕哪天程序抽风突然开始乱买?(虽然不太可能)

TOP

返回列表