量化策略
布林带策略
布林带/布林线/保利加通道(Bollinger Band):由三条轨道线组成,其中上下两条分别可以看成是价格的压力线和支撑线,在两条线之间是一条价格平均线
计算公式:
中间线 = 20日均线
up线 = 20日均线 + N*SD(20日收盘价)
down线 = 20日均线 - N*SD(20日收盘价)
(N通常2倍,SD价格的标准差)
#聚宽Boll逢高轨卖出,逢低轨买入策略代码 from jqdata import * def initialize(context): #初始化 #设置基准 set_benchmark('000300.XSHG') #设置复权,使用真实价格 set_option('use_real_price',True) #设置订单成本cost(close_tax印花税,open_commission买入佣金,close_commission卖出佣金,min_commission最小佣金5元,type类型选择股票) set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003,min_commission=5), type='stock') #设置security证券标的 g.security = ['600036.XSHG'] g.N = 2 #2倍 g.ma_days20 = 20 #20天 def handle_data(context,data): #handle句柄表示对象,默认每天调用一次 cach = context.portfolio.available_cash #可获得的现金 for stock in g.security: #获取往前20天的收盘价--计算出BOLL的上中下轨道--判断是否突破上下轨道,突破卖出,下破买入 price_days20 = attribute_history(stock,20)['close'] middle = price_days20.mean() upper = middle + g.N * price_days20.std() lower = middle - g.N * price_days20.std() #获得现在current时间股票价格 p = get_current_data()[stock].day_open #判断是否突破,突破卖出,跌破买入。并且是否持仓 if p > upper and stock in context.portfolio.positions: order_target(stock,0) if p < lower and stock not in context.portfolio.positions: order_target(stock,cach)
PEG策略
彼得林奇:任何一家公司股票如果定价合理的话,市盈率就会与收益增长率相等。
每股收益(EPS)
股价(P)
市盈率(PE)=P/EPS
收益增长率(G)=(EPSi-EPSi-1)/ESPi-1
PEG=PE/G/100
PEG越低,代表股价被低估可能性越大,股价会上涨的可能性就越大。
PEG是一个综合指标,既考查价值,有兼顾成长性。PEG估值法适合应用于成长型公司。
(PS:过滤掉收益率或收益增长率为负的情况)
#彼得林奇PEG策略 #PEG = 市盈率PE/收益增长率G/100 from jqdata import * def initialize(context): #初始化 #设置基准 set_benchmark('000300.XSHG') #设置复权,使用真实价格 set_option('use_real_price',True) #设置订单成本cost(close_tax印花税,open_commission买入佣金,close_commission卖出佣金,min_commission最小佣金5元,type类型选择股票) set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003,min_commission=5), type='stock') #设置security股票池,最终操作股票数g.N g.security = get_index_stocks('000300.XSHG') g.N = 20 run_monthly(handle,1) def handle(context): #handle句柄表示对象,默认每天调用一次 #调用财务数据,查询query(code代码,ratio市盈率,indicator财务数据.净利润增长率).filter(valuation市值数据.代码集) df = get_fundamentals(query(valuation.code,valuation.pe_ratio,indicator.inc_net_profit_year_on_year).filter(valuation.code.in_(g.security))) #排除负数 df = df[(df['pe_ratio']>0)&(df['inc_net_profit_year_on_year']>0)] #计算PEG,同时排序获得前10排的元素赋值给df df['PEG'] = df['pe_ratio']/df['inc_net_profit_year_on_year']/100 df = df.sort_values('PEG')[:g.N] #拿到满足条件的df所有代码,检索持仓信息,卖出不在持仓信息哦股票 #用列表生成式生成准备买的股票池,用for循环分别买入操作 tohold = df['code'].values for stock in context.portfolio.positions: if stock not in tohold: order_target(stock,0) tobuy = [stock for stock in tohold if stock not in context.portfolio.positions] #计算现金,分批买入 cash = context.portfolio.available_cash n = cash // len(tobuy) for stock in tobuy: order_value(stock,n)
羊驼交易策略
海龟交易策略
唐奇安通道:
- 上线 = Max(前N个交易日的最高价)
- 下线 = Min(前N个交易日的最低价)
- 中线 = (上线 + 下线) / 2

海龟交易法则:核心
- 造成的损失不要超过总仓位的 k%
True Range(一天内波动量)
- TrueRange = Maximum( H最高价 - L最低价, H最高价 - PDC前一天收盘价, PDC前一天收盘价 - L最低价)
N值计算
N值是仓位管理的核心,涉及加仓及止损。另外,N值与技术指标平均真实波幅 ATR很相似
首先介绍真实波幅: 真实波幅是以下三个值中的最大值
1、当前交易日最高价和最低价的波幅
2、前一交易日的收盘价与当前交易日最高价的波幅
3、前一交易日的收盘价与当前交易日最低价的波幅
用公式写就是:
TrueRange=Max(High−Low,abs(High−PreClose),abs(PreClose−Low))
接下来,N值计算公式为:
N=(PreN[−19:]+TrueRange)/20
其中 preN为前面N值,TrueRange为当前的真实波幅,此公式的真是含义为计算之前20天(包括今天在内)的N的平均值
另外,有些海龟交易系统用的是ATR来代替N值,ATR为真实波幅的20日平均。
买卖单位及首次建仓
先给出公式:
Unit=(1%∗Account)/N
首次建仓的时候,当捕捉到趋势,即价格突破唐奇安上轨时,买入1个unit。
其意义就是,让一个N值的波动与你总资金1%的波动对应,如果买入1unit单位的资产,当天震幅使得总资产的变化不超过1%。例如:
现在你有10万元资金,1%波动就是1000元。假如标X的N值为0.2元,1000元÷0.2元=5000股。也就是说,你的第一笔仓位应该是在其突破上轨(假设为5元)时立刻买入5000股,耗资25000元。
加仓
若股价在上一次买入(或加仓)的基础上上涨了0.5N,则加仓一个Unit。
接上面的例子:假如N值仍为0.2。
价格来到 5 + 0.2*0.5 = 5.1时,加仓1个Unit,买入5000股,耗资25500元,剩余资金 49500元
价格来到 5.1 + 0.2*0.5 = 5.2 时再加仓1个unit。买入5000股,耗资26000元,剩余资金 23500元
动态止损
当价格比最后一次买入价格下跌2N时,则卖出全部头寸止损。
接上面的例子,最后一次加仓价格为5.2。假如此时N值0.2元。 当价格下跌到 5.2 - 2*0.2 = 4.8元时,清仓。
持仓成本为 (5+5.1+5.2)*5000/15000 = 5.1元。 此时亏损 (5.1-4.8)*15000 = 4500元 对于10万来说 这波亏损4.5%
止盈
当股价跌破10日唐奇安通道下沿,清空头寸结束本次交易。
——
原始的海龟交易采用唐奇安通道来捕捉趋势,虽然能捕捉到大趋势,但是在震荡的情况下表现不如人意,不过这也是所有趋势型策略的通病。但是回测小的特点可以应用在资金管理上,择时可以看看多因子、动量反转等。
#海归策略 # 2020-01-01 到 2020-12-1, ¥1000000, 分钟 from jqdata import * def initialize(context): #初始化 #设置基准 #set_benchmark('000063.XSHG') #设置复权,使用真实价格 set_option('use_real_price',True) #设置订单成本cost(close_tax印花税,open_commission买入佣金,close_commission卖出佣金,min_commission最小佣金5元,type类型选择股票) set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003,min_commission=5), type='stock') g.total_days = 0#运行总天数 g.security = '000002.XSHE' g.N = [] #接收每天波动平均值N g.sys1_amount = 0 #系统1建的仓数 g.sys2_amount = 0 #系统2建的仓数 g.loss = 0.1 #可承受最大损失率 g.adjust = 0.8 #若超过最大损失率,则调整为0.8 g.ratio = 0.8 #系统1配置金额占总金额比例 g.system1_system2 = True #系统1执行则系统2不执行 #设置策略参数 g.short_in_date = 20 g.short_out_date = 10 g.long_in_date = 55 g.long_out_date = 20 g.unit = 1000 #初始买卖单位 #每波动1个的最小单位,1手股票的价格变化 #国内最小单位0.01元,最低买100股 0.01*100=1 g.dollars_per_share = 1 g.unit_limit = 4 #开单限制limit 在4个买卖单位 g.break_price1 = 0 #系统1的突破价格 g.break_price2 = 0 #系统2的突破价格 ''' ======================每天开盘前======================== ''' #开盘前运行函数 def before_trading_start(context): set_slip_fee(context) #设置,滑点slip,费用fee def set_slip_fee(context): #根据不同时间区间,设置手续费 dt = context.current_dt ##获取当前时间+日期,获取当前日期为(ontext.current_dt.date()) if dt>datetime.datetime(2013,1, 1): set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003,min_commission=5), type='stock') elif dt<datetime.date(2013,1, 1): set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003,min_commission=5), type='stock') ''' ======================正式交易时间======================== ''' def handle_data(context,data): #------每天开盘时间计算出20天的N dt = context.current_dt #当前日期时间 current_price1 = data[g.security].price #当前价格 if dt.hour==9 and dt.minute==30: print('--------------------') g.total_days += 1 calculate_N() #计算calculate #------大于20天后进行(资金,仓位)配置啊 if g.total_days > 20: #------总资产,可用现金,操作比率 value = context.portfolio.portfolio_value #total_value cash = context.portfolio.cash #available_cash #当两个系统仓位都为0时,复位资金比率 if g.sys1_amount == 0 and g.sys1_amount == 0: #若总资产小于 初始资金比率, 则降低20%资产变量和可用现金变量 if value < (1-g.loss)*context.portfolio.starting_cash: value*=g.adjust cash*=g.adjust #------按照波动量计算买卖手数单位 #根据本策略,计算买卖单位(最大损失的1%进行下单) #每波动1个的最小单位,1手股票的价格变化 #国内最小单位0.01元,最低买100股 0.01*100=1 dollar_volatility = g.dollars_per_share*(g.N)[-1] g.unit = value*0.01/dollar_volatility #------系统操作1(如果市场没有订单,则进行开单函数验证) g.system1_system2 = True if g.sys1_amount == 0: #传入参数(当前价格,仓位比率金额,入市系统时机参数) market_in(current_price1,g.ratio*cash,g.short_in_date) #否则有订单,则加仓或者出 else: #先调入止损函数,再调入加仓,离场函数 stop_loss(current_price1) #传入参数(当前价格,仓位比率金额,入市系统时机参数) market_add(current_price1,g.ratio*cash,g.short_in_date) #传入参数(当前价格,仓位比率金额,出市系统时机参数) market_out(current_price1,g.short_out_date) #------系统操作2 g.system1_system2 == False if g.sys2_amount == 0: #传入参数(当前价格,仓位比率金额,入市系统时机参数) market_in(current_price1,(1-g.ratio)*cash,g.long_in_date) #否则有订单,则加仓或者出 else: #先调入止损函数,再调入加仓,离场函数 stop_loss(current_price1) #传入参数(当前价格,仓位比率金额,入市系统时机参数) market_add(current_price1,(1-g.ratio*cash),g.long_in_date) #传入参数(当前价格,仓位比率金额,出市系统时机参数) market_out(current_price1,g.long_out_date) ''' ======================调用函数======================== ''' #计算calculate_N的值 def calculate_N(): #交易总天数小于20天,N值为每天波动幅度True_Range的平均值(最大波动价格的均值) if g.total_days <= 20: #取得股票价格表,循环计算当天的波动幅度(最高价,最低价,前天收盘价) price = attribute_history(g.security,g.total_days,'1d',('high','low','pre_close')) lst = [] #循环1-20天计算每天波动传入lst列表,然后均值运算 for c_day in range(0, g.total_days): H_L = price['high'][c_day] - price['low'][c_day] #当天最高-最低 H_C = price['high'][c_day] - price['pre_close'][c_day] L_C = price['pre_close'][c_day]- price['low'][c_day] True_Range = max(H_L,H_C,L_C)#计算最大动量值 lst.append(True_Range) #把当天列表序列转换成数组,均值运算得出单个波动值N,把每天的N加入接收列表 current_N = np.mean(np.array(lst)) (g.N).append(current_N) else: #交易天数大于20,就只以当天数据计算(前面的N 已经计算出来直接调用) price = attribute_history(g.security,1,'1d',('high','low','pre_close')) H_L = price['high'][0] - price['low'][0] #当天最高-最低 H_C = price['high'][0] - price['pre_close'][0] L_C = price['pre_close'][0] - price['low'][0] True_Range = max(H_L,H_C,L_C) #最终N值公式:N=(当前波动量+19*(g.N)[-1])/20 #(g.N)[-1]是列表最后一个值,也就是上一个交易日的动量值 current_N = (True_Range+19*(g.N)[-1])/20 (g.N).append(current_N) #没有订单的开仓函数(入市以突破唐奇安通道Max(N20),收破唐奇安通道Min(N10)出) def market_in(current_price1,cash,in_out): price = attribute_history(g.security,in_out,'1d',('close')) if current_price1 > max(price['close']): #买单前计算可买股份数 >= 一个买进单位则买入 num_of_shares = cash/current_price1 if num_of_shares >= g.unit: print('空仓买入前打印买入价格') print('current_price1') print(max(price['close'])) #系统1开单,否则就是系统2开单 if g.system1_system2 == True: #波动1个单位unit为1%,总仓位小于4个单位 if g.sys1_amount < int(g.unit_limit*g.unit): order(g.security,int(g.unit)) #买入一个单位 g.sys1_amount += int(g.unit) #持仓单位加一个 g.break_price1 = current_price1 #记录系统1的开仓价格 else: if g.sys2_amount < int(g.unit_limit*g.unit): order(g.security,int(g.unit)) #买入一个单位 g.sys2_amount += int(g.unit) #持仓单位加一个 g.break_price2 = current_price1 #记录系统2的开仓价格 #加仓函数 def market_add(x,cash,in_date): if g.system1_system2 ==True: break_price = g.break_price1 #获取系统1开仓价格 else: break_price = g.break_price2 #获取系统2开仓价格 #每上涨前一个波动值的0.5倍,加仓一个单位 if x >= break_price + 0.5*(g.N)[-1]: #开仓前计算可买股份,大于1个买入单位则买入 num_of_shares = cash/x if num_of_shares >= g.unit: print('加仓买入前打印订单仓位,买入价格') print(g.sys1_amount) print(g.sys2_amount) print(x) print(break_price + 0.5*(g.N)[-1]) if g.system1_system2 == True: #波动1个单位unit为1%,总仓位小于4个单位 if g.sys1_amount < int(g.unit_limit*g.unit): order(g.security,int(g.unit)) #买入一个单位 g.sys1_amount += int(g.unit) #持仓单位加一个 g.break_price1 = x #记录系统1的开仓价格 else: if g.sys2_amount < int(g.unit_limit*g.unit): order(g.security,int(g.unit)) #买入一个单位 g.sys2_amount += int(g.unit) #持仓单位加一个 g.break_price2 = x #记录系统2的开仓价格 #离场函数 def market_out(x,out_date): price = attribute_history(g.security, out_date,'1d',('close')) if x < min(price['close']): print('开始离场') print(type(x)) print('离场价格%.2f'%x) #print('唐奇安通道N10价:%.2f'%min(price['close'])) if g.system1_system2 == True: if g.sys1_amount > 0: order(g.security,-g.sys1_amount) #卖出以后,仓位数重置标记为0 g.sys1_amount = 0 else: if g.sys2_amount > 0: order(g.security,-g.sys2_amount) #卖出以后,仓位数重置标记为0 g.sys2_amount = 0 #止损函数 def stop_loss(x): if g.system1_system2 == True: break_price = g.break_price1 #获取系统1开仓价格 else: break_price = g.break_price2 #获取系统2开仓价格 #损失大于2N,则卖出 if x < (break_price - 2*(g.N)[-1]): print('止损开始') print('当前价格:%.2f'%x) print('开仓价-2倍的波动价N:%.2f'%(break_price - 2*(g.N)[-1])) if g.system1_system2 == True: order(g.security,-g.sys1_amount) g.sys1_amount = 0 else: order(g.security,-g.sys2_amount) g.sys2_amount = 0

浙公网安备 33010602011771号