本文仅为学习笔记,无法保证正确性,不可作为交易参考。
策略——生命线(MA20)买卖,MA为滑动平均线,取N天均值。
1、算法逻辑
- 分别选取沪深300及创业板个股进行测试;
- 突破生命线买入1%,跌破生命线5%卖出;
- 按分钟回测,仓位90%以下,每分钟在股票池选取5只以市价模式开新仓;
2、代码实现(以创业板为例)
# 导入函数库
import numpy as np
import pandas as pd
from datetime import timedelta
from jqdata import *
from jqlib.technical_analysis import MA
import time
# 初始化函数,设定基准等等
def initialize(context):
# 设定沪深300作为基准
g.stop_profit_pct = 0.2
g.stop_loss_pct = -0.15
g.low_pct = 0.05
g.code = '399006.XSHE'
g.stock_pool_nums = 100
g.ma_period = 20
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
# log.set_level('order', 'error')
### 股票相关设定 ###
# 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
## 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'000300.XSHG'或'510300.XSHG'是一样的)
# 开盘前运行
run_daily(before_market_open, time='before_open', reference_security='000300.XSHG')
# 开盘时运行
# run_daily(market_open, time='open', reference_security='000300.XSHG')
# 收盘后运行
run_daily(after_market_close, time='after_close', reference_security='000300.XSHG')
## 开盘前运行函数
def before_market_open(context):
# 输出运行时间
g.stock_list = get_index_stocks(g.code)
g.stocks_pool = [s for s in np.random.choice(g.stock_list, size=g.stock_pool_nums) if not (get_current_data()[s].paused or get_current_data()[s].is_st)]
yesterday_price = history(1, '1d', 'close', g.stocks_pool, skip_paused=True, fq='pre').T
# log.info(yesterday_price)
ma20 = MA(yesterday_price.index, context.current_dt.date() - timedelta(days=1), timeperiod=g.ma_period)
k, v = list(zip(*ma20.items()))
ma20_df = pd.DataFrame(list(v), index=list(k), columns=['v'])
# log.info(ma20_df)
yesterday_price.columns = ['v']
temp = yesterday_price.copy()
temp = temp.merge(ma20_df, how='left', left_index=True, right_index=True).drop_duplicates()
temp['diff'] = temp['v_x'] - temp['v_y']
# log.info(temp)
# temp = temp.merge(lower_ma20, how='left', left_index=True, right_index=True)
# lower_ma20 = yesterday_price - ma20_df
lower_ma20 = temp['diff']
# lower_ma20.columns = 'v'
# log.info(lower_ma20[lower_ma20 < 0].index)
g.stocks_pool = set(lower_ma20[lower_ma20 < 0].index)
g.per_stock_cost = context.portfolio.available_cash / g.stock_pool_nums * 5
g.order_times_max = g.stock_pool_nums * 11
g.order_times = 0
g.empty_flag = False
## 开盘时运行函数
# def market_open(context):
def handle_data(context, data):
# while (context.portfolio.available_cash > 0.1 * context.portfolio.total_value) and (g.order_times <= g.order_times_max):
for s in range(0, 5):
if (context.portfolio.available_cash > 0.1 * context.portfolio.total_value) and (not g.empty_flag):
# log.info('handel {}'.format(g.stocks_pool))
try:
s = g.stocks_pool.pop()
except KeyError:
g.empty_flag = True
break
price = data[s].close
ma20_today = MA(s, context.current_dt.date(), timeperiod=g.ma_period).get(s)
log.info('s:{},p:{},ma:{}'.format(s, price, ma20_today))
if price > 1.01 * ma20_today:
order_target_value(s, g.per_stock_cost, MarketOrderStyle())
else:
g.stocks_pool.add(s)
for s in [s for s in context.portfolio.positions.keys() if (not get_current_data()[s].paused) and (data[s].close < 0.95 * MA(s, context.current_dt.date(), timeperiod=g.ma_period).get(s))]:
order_target(s, 0, MarketOrderStyle())
# time.sleep(60)
# ## 收盘后运行函数
def after_market_close(context):
orders = get_open_orders()
for o in orders.values():
cancel_order(o)
# log.info(str('函数运行时间(after_market_close):'+str(context.current_dt.time())))
# #得到当天所有成交记录
# trades = get_trades()
# for _trade in trades.values():
# log.info('成交记录:'+str(_trade))
# log.info('一天结束')
# log.info('##############################################################')
3、回测结果
4、总结
- handle_data按分钟回测时,每分钟执行1次,注意循环特别是while语句的使用;
- jqlib.technical_analysis包含常见指标;
- 在开盘前调用history不能取到今天的数据