本帖最后由 老刘1号 于 2023-3-3 12:32 编辑
论坛正好有python板块,发来玩玩
回测环境:聚宽量化- import talib
- from prettytable import PrettyTable
- import pandas
- import datetime
- import time
- from jqdata import *
-
-
- def initialize(context):
- # 初始化变量
- g.buy_stock_count = 20
-
- # 设定基准为沪深300
- set_benchmark('000300.XSHG')
- # True为开启动态复权模式,使用真实价格交易
- set_option('use_real_price', True)
- # 设定避免未来函数模式
- set_option("avoid_future_data", True)
- # 股票类交易手续费和滑点
- set_order_cost(
- OrderCost(
- open_tax =0,
- close_tax =0.001,
- open_commission =0.0003,
- close_commission=0.0003,
- min_commission =5),
- type ='stock')
- set_slippage(FixedSlippage(0.02))
- # 设置日志级别
- log.set_level('order', 'error')
- # 每天运行
- run_daily(daily,'open')
-
- def daily(context):
- adjust_position(context, select_stocks(context))
-
- def select_stocks(context):
- #沪深股通持仓
- df=finance.run_query(
- query(finance.STK_HK_HOLD_INFO)\
- .filter(finance.STK_HK_HOLD_INFO.day>=context.previous_date)\
- .filter(finance.STK_HK_HOLD_INFO.link_id.in_([310001,310002])))
- stocks = [ {
- 'code' : code,
- 'name' : name,
- 'number' : share_number,
- 'price' : price,
- 'value' : share_number * price
- } for code, name, share_number, price in zip(
- list(df.code), \
- list(df.name), \
- list(df.share_number), \
- list(get_price(
- security=list(df.code),
- panel=False,
- start_date=context.previous_date,
- end_date=context.previous_date,
- frequency='daily',
- fields='close',
- skip_paused=False,
- fq='pre')['close'])
- )]
- #按持仓市值排序
- stocks = sorted(stocks, key = lambda stock: stock['value'], reverse=True)
- #for stock in filter((lambda x: x['price'] < 200), stocks[:40]):
- #print("{} {} {} {}".format(stock['code'], stock['name'], stock['value'], stock['price']))
- #print([i['code'] for i in filter((lambda x: x['price'] < 200), stocks[:40])])
- return [stock['code'] for stock in stocks][:g.buy_stock_count]
-
- def filter_paused_and_st_stock(stock_list):
- current_data = get_current_data()
- return [stock for stock in stock_list if not current_data[stock].paused
- and not current_data[stock].is_st and 'ST' not in current_data[stock].
- name and '*' not in current_data[stock].name and '退' not in current_data[stock].name]
-
- def adjust_position(context, buy_stocks):
- # 现持仓的股票,如果不在“目标池”中,且未涨停,就卖出
- if len(context.portfolio.positions)>0:
- last_prices = history(1, '1m', 'close', security_list=list(context.portfolio.positions.keys()))
- for stock in list(context.portfolio.positions.keys()):
- if stock not in buy_stocks :
- curr_data = get_current_data()
- if last_prices[stock][-1] < curr_data[stock].high_limit:
- order_target_value(stock, 0)
- # 依次买入“目标池”中的股票
- for stock in buy_stocks:
- position_count = len(context.portfolio.positions)
- if g.buy_stock_count > position_count:
- value = context.portfolio.cash / (g.buy_stock_count - position_count)
- if context.portfolio.positions[stock].total_amount == 0:
- stock_price = get_price(
- security=stock,
- panel=False,
- start_date=context.previous_date,
- end_date=context.previous_date,
- frequency='daily',
- fields='close',
- skip_paused=False,
- fq='pre')['close']
- order(stock, (((context.portfolio.available_cash+context.portfolio.positions_value+ context.portfolio.returns)/g.buy_stock_count)/stock_price)//100*100)
-
- def show_stock(stock):
- '''
- 获取股票代码的显示信息
- :param stock: 股票代码,例如: '603822.SH'
- :return: str,例如:'603822 嘉澳环保'
- '''
- return "%s %s" % (stock[:6], get_security_info(stock).display_name)
-
- def get_portfolio_info_text(context,new_stocks,op_sfs=[0]):
- # new_stocks是需要持仓的股票列表
- sub_str = ''
- table = PrettyTable(["仓号","股票", "持仓", "当前价", "盈亏率","持仓比"])
- for sf_id in range(len(context.subportfolios)):
- cash = context.subportfolios[sf_id].cash
- p_value = context.subportfolios[sf_id].positions_value
- total_values = p_value +cash
- if sf_id in op_sfs:
- sf_id_str = str(sf_id) + ' *'
- else:
- sf_id_str = str(sf_id)
- for stock in list(context.subportfolios[sf_id].long_positions.keys()):
- position = context.subportfolios[sf_id].long_positions[stock]
- if sf_id in op_sfs and stock in new_stocks:
- stock_str = show_stock(stock) + ' *'
- else:
- stock_str = show_stock(stock)
- stock_raite = (position.total_amount * position.price) / total_values * 100
- table.add_row([sf_id_str,
- stock_str,
- position.total_amount,
- position.price,
- "%.2f%%"%((position.price - position.avg_cost) / position.avg_cost * 100),
- "%.2f%%"%(stock_raite)]
- )
- if sf_id < len(context.subportfolios) - 1:
- table.add_row(['----','---------------','-----','----','-----','-----'])
- sub_str += '[仓号: %d] [总值:%d] [持股数:%d] [仓位:%.2f%%] \n'%(sf_id, total_values,
- len(context.subportfolios[sf_id].long_positions), p_value*100/(cash+p_value))
- log.info('持仓详情:\n' + sub_str + str(table))
复制代码 回测数据- 回测时间
- 2022-02-08 20:20:53
- 回测区间
- 2017-03-20 - 2022-02-07
- 策略收益
- 129.20%
- 策略年化收益
- 19.07%
- 超额收益
- 70.43%
- 基准收益
- 34.48%
- 阿尔法
- 0.128
- 贝塔
- 0.915
- 夏普比率
- 0.759
- 胜率
- 0.846
- 盈亏比
- 13.917
- 最大回撤
- 28.29%
- 索提诺比率
- 1.082
- 日均超额收益
- 0.05%
- 超额收益最大回撤
- 13.77%
- 超额收益夏普比率
- 0.857
- 日胜率
- 0.536
- 盈利次数
- 11
- 亏损次数
- 2
- 信息比率
- 1.376
- 策略波动率
- 0.199
- 基准波动率
- 0.193
- 最大回撤区间
- 2021/02/10,2022/01/28
复制代码
|