布林带策略
布林带/布林线/保利加通道(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的平均值
买卖单位及首次建仓
先给出公式:
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