您获取的数据已经是前复权的数据。停牌的数据自动用停牌前的数据来填充,但成交量为0。
默认万三手续费,千一印花税
Max Drawdown=Max(Px−Py)/PxPx,Py=策略某日股票和现金的总价值,y>x
Total Returns=(Pend−Pstart)/Pstart∗100%Pend=策略最终股票和现金的总价值Pstart=策略开始股票和现金的总价值
Benchmark Returns=(Mend−Mstart)/Mstart∗100%Mend=基准最终价值Mstart=基准开始价值
Sharpe Ratio=(Rp−Rf)/σpRp=策略年化收益率Rf=无风险利率(默认0.04)σp=策略收益波动率
Beta=βp=Cov(Dp,Dm)/Var(Dm)
βp=策略beta值
Alpha值 解释
Beta=βp=Cov(Dp,Dm)/Var(Dm)
Var(Dm)=基准每日收益的方差
Beta值 解释
1 2 3 4 |
def init(context): schedule_function(my_func,DateRule.every_day(),TimeRule.once_per_day(10,30)) def my_func(context,data): log.info("%s %s" % (data.days_current("sha-601318")["sha-601318"],data.now) ) |
1 2 3 4 5 6 7 8 9 |
def init(context): schedule_function(test,DateRule.every_day(),TimeRule.market_open(30) ) context.bench_mark="sha-600498" context.stock1="sha-600000" def test(context,data): if context.portfolio.positions.has_key(context.stock1): order_target_percent(context.stock1, 0) else: order_target_percent(context.stock1, 100) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def init(context): # 定义一个全局变量, 保存要操作的股票 # 000001(股票:平安银行) context.stock1 = 'sza-000001' # 定义每天开盘之后30分钟调用 schedule_function(test_func,DateRule.every_day(),TimeRule.once_per_day() ) #定义 ma5=EMAFactor(5,'close') reg_factor("ma5",ma5) def test_func(context, data): output=factor_output("ma5",context.stock1) sma5=output["ma5"] current_price=data.days_current("sza-000001") if current_price>1.01*sma5: order(context.stock1,10000) record("ma5",sma5) |
1 2 3 4 |
def init(context): lst=find_by_group("all-stocks") context.benchMark="sha-600498" context.slippage=0.003 |
镭矿平台里并没有全局股票集的概念,而是调用具体方法的时候,传入股票集合。例:
1 2 |
context.stocks=["sha-600000","sza-000001"] current_prices=data.days_current(context.stocks,"close") |
sha-
,深市代码里都带有前缀 sza-
Data对象可以随时随地获取任何时间级别的数据(日线、小时线、分钟线数据)。
data.days(stock_list,field,num,df) | 返回日线历史数据,数组 |
data.days_current(stock_list) | 当前日线数据 |
data.days_prior(stock_list,offset) | 前期日线数据,offset为偏移量,一个正数,表示前几天 |
data.hours(stock_list,field,num,df) | 返回小时线历史数据,数组 |
data.hours_current | 当前小时线数据 |
data.hours_prior | 前期 小时线数据,offset为偏移量,一个正数,表示前几天 |
data.minutes(stock_list,field,num,df) | 返回分钟线历史数据,数组 |
data.minutes_current | 当前分钟线数据 |
data.minutes_prior | 前期分钟线数据,offset为偏移量,一个正数,表示前几天 |
示例代码如下:
1 2 3 4 |
context.stocks=["sha-600498"] lst=data.minutes(context.stocks,"close",10)["sha-600498"] curr=data.hours_current(context.stocks,"close")["sha-600498"] prior=data.days_prior(context.stocks,"close",2)["sha-600498"] |
其中,lst为数组,数组元素为float类型,返回sha-600498前10天的收盘价
context存储了本次测试的相关环境,另外你可以使用context存储你需要的全局变量
context.my_stock=1
context.my_lst=[3,4,5,6,7,8]
我们选定了股票 sha-601988 的作为判断您策略好坏和一系列风险值计算的基准. 您也可以使用 context.bench_mark 指定其他股票/指数的价格作为基准,示例代码如下:
1 |
context.bench_mark="sha-601318" |
1 2 3 |
if context.portfolio.cash > 0: order_percent(context.s,100) log.info(context.portfolio.positions[context.s][price]) |
security
股票代码price
当前价格avg_cost
平均成本amount
持有数量
1 |
record("kpi",kpiValue); |
log.info
log.debug
log.warn
log.error
1 2 3 |
if context.portfolio.cash > 0: order_percent(context.s,100) log.info(context.portfolio.positions[context.s][price]) |
security
股票代码price
当前价格avg_cost
平均成本amount
持有数量
Trade 对象,可以获取成交数据
time
交易时间amount
交易证券的数量security
证券名称price
成交价格is_buy
True表示是买入成交单,Fasle表示是卖出成交单comment
买入时代码里写入的注释文本示例代码如下:
1 2 3 |
order_value("sha-601318",1000) df=pd.DataFrame(get_open_assets("sha-601318")) log.info(df.loc("sha-601318")) |
get_open_assets(security)
示例代码如下:
1 2 3 |
order_value("sha-601318",1000) df=pd.DataFrame(get_closed_assets("sha-601318")) log.info(df.loc("sha-601318"])) |
get_closed_assets(security)
1 2 |
lst1=find_by_group("all-stocks") lst2=find_by_group("hs300") |
1 |
schedule_function(func=None,date_rule=None,time_rule=None) |
定时函数需传入函数名,DateRule,TimeRule 示例:
1 2 3 4 |
def init(context): schedule_function(test_func,DateRule.every_day(),TimeRule.MarketOpenRule()) def test_func(context,data): log.info(data.dt) |
如上,想schedule_function里传入了test_func,这就是自定义方法的方法名。这段代码定义了每天市场开盘后都打印一下当前时间。
DateRule定义了定时事件具体到天怎么执行。
1 |
DateRule.every_day() |
这个方法返回一个代表每天执行的DateRule
1 |
DateRule.month(offset) |
这个方法返回一个代表每个月执行的DateRule,offset 代表当月的第几个交易日,DateRule.month(1) 代表每月的第一个交易日执行
1 |
DateRule.week(offset) |
这个方法返回一个代表每个星期执行的DateRule,offset 代表每个星期的第几个交易日,
DateRule.week(1) 代表每周的第一个交易日执行(大多数情况下是周一)
1 |
DateRule.last_day() |
这个方法表示只在上一个交易日执行。一般用于选股、计算等一次性任务。
TimeRule定义了定时事件具体到当天的时间点怎么执行。现在有5个方法。
1 |
TimeRule.MarketOpenRule(offset_minutes=0) |
这个方法返回一个Rule,代表开盘后候执行。offset_minutes表示开盘后多少分钟时执行
1 |
TimeRule.MarketCloseRule(offset_minutes=0) |
这个方法返回一个Rule,代表收盘前执行。offset_minutes表示收盘前多少分钟时执行
1 |
TimeRule.once_per_day(hours=0,minutes=0) |
这个方法返回一个Rule,代表一天的某一个时间点执行一次。当被错误地指定为非交易时间时,系统将强制修正为10:00执行。
1 |
TimeRule.every_hour() |
这个方法返回一个Rule,代表每个小时时刻执行一次。
1 |
TimeRule.every_minute() |
这个方法返回一个Rule,代表每一分钟执行一次。
一般仅做一些短线止损止盈,不做太复杂的逻辑。
除了以上使用DateRule,TimeRule自定义定时函数之外,镭矿还提供几个保留函数名,这几个函数名声明后就会被自动注册为定时函数的方法名。
1 2 3 |
every_day every_hour every_minute |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
from factors.max_factor import MAXFactor from factors.min_factor import MINFactor def init(context): context.lst=find_by_group("all-stocks") universe.extend(lst) context.bench_mark="sha-601918" context.slippage=0.003 context.num=0 f1=MAXFactor(30,"close") f2=MINFactor(30,"close") add_pipeline("max",f1) add_pipeline("min",f2) add_pipeline_expr("rate","max/min") add_pipeline_expr("rate2","int(rate*100)") def every_day(context,data): lst=factor_output("rate",context.lst).sort("rate",ascending=[1]).head(5).index for stock in lst: mark(stock) log.info(stock) |
EMAFactor ( window_length
, field
) 返回时间区间的EMA
Note
EMA(Exponential Moving Average),指数平均数指标。也叫EXPMA指标,它也是一种趋向类指标,指数平均数指标是以指数式递减加权的移动平均。在EMA指标中,每天价格的权重系数以指数等比形式缩小。时间越靠近当今时刻,它的权重越大,说明EMA函数对近期的价格加强了权重比,更能及时反映近期价格波动情况。
window_length
:类型int,历史时间窗口长度field
:可为’open’,’close’,’high’,’low’,’volume’
例如示例代码如下:
1 2 3 4 5 6 7 |
def init(context): context.s="sha-601998" f1=EMAFactor(14,'close') reg_factor("ema",f1) def every_day(context,data): data=factor_output("ema",context.s) log.info("\n%s"%data) |
会打印出如下结果:
1 2 3 |
2016-07-14 11:18:48,498 INFO:ema sha-601988 3.684187 sha-601318 32.875111 |
RSIFactor ( window_length
, field
)返回RSI,Relative Strength Index,强弱指标
Note
RSI的原理简单来说是以数字计算的方法求出买卖双方的力量对比,譬如有100个人面对一件商品,如果50个人以上要买,竞相抬价,商品价格必涨。相反,如果50个人以上争着卖出,价格自然下跌。
强弱指标理论认为,任何市价的大涨或大跌,均在0-100之间变动,根据常态分配,认为RSI值多在30-70之间变动,通常80甚至90时被认为市场已到达超买状态,至此市场价格自然会回落调整。当价格低跌至30以下即被认为是超卖状态,市价将出现反弹回升。
window_length
:类型int,历史时间窗口长度field
:可为’open’,’close’,’high’,’low’,’volume’
例如示例代码如下:
1 2 3 4 5 6 7 |
def init(context): context.s="sha-601998" f1=RSIFactor(14,'close') reg_factor("rsi",f1) def every_day(context,data): data=factor_output("rsi",context.s) log.info("\n%s"%data) |
会打印出如下结果:
1 2 3 |
2016-07-14 11:27:35,511 INFO:rsi sha-601988 53.376574 sha-601318 51.919554 |
DMIFactor ( window_length
)返回DMI指标
Note
DMI指标共有+DI、-DI、ADX、ADXR四条线,也是它的四个参数值,它分为多空指标(+DI、-DI)和趋向指标(ADX、ADXR)两组指标.
window_length
:类型int,历史时间窗口长度field
:可为’open’,’close’,’high’,’low’,’volume’
1 2 3 4 5 6 7 |
def init(context): lst=find_by_group("sz50") f1=DMIFactor(14) reg_factor("abc",f1) def every_day(context,data): alldata=factor_output("abc_mdi",lst) log.info("\n%s"%alldata.head(3)) |
1 2 3 4 |
abc_adx abc_adxr abc_mdi abc_pdi sha-601998 54.469246 60.264924 9.037369 34.450496 sha-601857 56.354691 59.094876 10.986684 41.589345 sha-601688 61.831469 74.606265 13.149323 32.051018 |
BBANDSFactor ( window_length
, field
)返回指定field的布林带
window_length
:类型int,历史时间窗口长度field
:可为’open’,’close’,’high’,’low’,’volume’
1 2 3 4 5 6 7 8 9 10 11 12 |
def init(context): context.stocks=[] context.stocks.extend(['sha-600000', 'sza-300207', 'sza-002030', 'sza-300033', 'sha-600677', 'sha-600340', 'sza-300024', 'sha-600650', 'sza-300133', 'sza-000002', 'sha-600703', 'sza-300275', 'sza-002280', 'sha-600887','shz-000001' ]) context.bench_mark="sha-601318" context.slippage=0.003 f1=BBANDSFactor(14,"close") reg_factor("abc",f1) def every_day(context,data): alldata=factor_output("abc","shz-000001") record("lowerband",alldata["abc_lowerband"]) record("middleband",alldata["abc_middleband"]) record("upperband",alldata["abc_upperband"]) |
reg_factor(name,factor)
reg_expr(name,expr)
factor_output(factor_name,stock_list)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
max min rate rate2 sza-300189 8.20 6.71 1.222057 122 sza-300188 32.58 25.60 1.272656 127 sza-300187 34.66 29.60 1.170946 117 sza-300186 8.88 7.78 1.141388 114 sza-300185 6.74 5.55 1.214414 121 sza-300184 14.85 11.62 1.277969 127 sza-300183 52.69 47.42 1.111135 111 sza-300182 24.30 17.16 1.416084 141 sza-300181 16.14 12.49 1.292234 129 sza-300180 9.78 8.47 1.154664 115 sza-300061 18.24 16.29 1.119705 111 sza-002481 18.45 14.82 1.244939 124 sha-600297 10.05 6.87 1.462882 146 sza-002483 12.74 11.21 1.136485 113 sha-600295 9.54 8.48 1.125000 112 |
1 |
prev_ma60=factor_output("sma60",stock,"d1",-3)["sma60"] |
factor_output_df是factor_output返回DataFrame格式的版本
get_fundamentals(field_list,date_str) 返回 指定时间,所有股票集的指定财务数据字段
Note
简单来说就是以DataFrame存储所有股票相关指标的指定时间的数据信息,例如,查询股票sha-600000,2016年02月02号的 income_statDate,balance_capital_reserve_fund,valuation_pe_ratio字段信息,则可以调用此接口实现。查询到的有些结果是当天能看到的数据,而并不一定是当天发布的数据。比如一些季度数据,只是季度末发布。但你用任何日期都可以查询到结果,结果返回的就是你能看到的最近的季度数据。
- field_list:字符串类型,需要查询的字段列表,例 :”brief_bps,brief_roic”
- date_str:字符串类型,指定查询日期,格式为:20150331
- 也即:df=get_fundamentals(“brief_bps,brief_roic”,”20150331″)
- 返回类型DataFrame结构中,示例如下:
1 2 3 |
INFO: brief_bps brief_roic sza-300662 2.48 29.09 sza-300663 3.61 8.58 |
get_fundamentals_ratio(field1,field2,date_str=None) 返回 指定时间,所有股票集的指定财务数据字段field1与field2的比值
Note
很多财务字段看绝对值没有办法跟其他公司比较,这里提供了一个比值计算,方便用这个计算结果进行不同公司的比较。
1 2 3 4 5 6 7 8 9 10 11 |
| brief_basic_eps | eps | brief | | brief_bps | bps | brief | | brief_roe_fully_diluted | roe摊薄 | brief | | brief_roe_weighted_average | 加权roe | brief | | brief_roet | ROET | brief | | brief_roic | ROIC | brief | | brief_assets_liability_ratio | 资产负债比 | brief | | brief_liquid_ratio | 流动比率 | brief | | brief_quick_ratio | 速动比率 | brief | | brief_equity_multiplier | 权益乘数 | brief | | brief_net_profit_gross_revenue_ratio | 净利润比上营业总收入 | brief | |
1 2 3 4 5 6 7 |
| balance_liquid_assets | 流动资产总计 | balance | | balance_non_liquid_assets | 非流动资产总计 | balance | | balance_current_liability | 流动负债总计 | balance | | balance_non_current_liability | 非流动负债总计 | balance | | balance_assets | 资产总计 | balance | | balance_liability | 负债总计 | balance | | balance_owners_equity | 所有者权益总计 | balance | |
1 2 3 4 5 6 7 8 9 |
| cashflow_operating_activities_in | 经营活动流入 | cashflow | | cashflow_operating_activities_out | 经营活动流出 | cashflow | | cashflow_investing_activities_in | 投资活动流入 | cashflow | | cashflow_investing_activities_out | 投资活动流出 | cashflow | | cashflow_financing_activities_in | 筹资活动流入 | cashflow | | cashflow_financing_activities_out | 筹资活动流出 | cashflow | | cashflow_operating_activities_total | 经营活动总计 | cashflow | | cashflow_investing_activities_total | 投资活动总计 | cashflow | | cashflow_financing_activities_total | 筹资活动总计 | cashflow | |
1 2 3 4 5 6 7 8 9 10 11 |
| profit_operating_income | 营业收入 | profit | | profit_overhead_costs | 营业成本 | profit | | profit_selling_expenses | 销售费用 | profit | | profit_adminisstrative_expenses | 管理费用 | profit | | profit_financial_expenses | 财务费用 | profit | | profit_changes_in_the_fair_value | 公允价值变动收益 | profit | | profit_net_investment_income | 投资净收益 | profit | | profit_operating_profit | 营业利润 | profit | | profit_total_profit | 利润总额(含非营业收入支出影响) | profit | | profit_net_profit | 净利润 | profit | | profit_net_profit_attributable_to_the_parent_company | 归属于母公司所有者的净利润 | profit | |
1 2 3 4 5 6 7 |
| cs_total_stock_issue | 总股本 | capital_structure | | cs_total_stock_issue_a | 流通A股 | capital_structure | | cs_limited_total | 有限售条件股份总额 | capital_structure | | cs_limited_country | 有限售条件股份-国家持股 | capital_structure | | cs_limited_state_own_Legal_person | 有限售条件股份-国有法人持股 | capital_structure | | cs_limited_foreign_capital | 有限售条件股份-外资持股 | capital_structure | | cs_limited_executives | 有限售条件股份-高管持股 | capital_structure | |
history相当于上面的data.days data.hours data.minutes 三个函数的另一个包装。
1 |
history(stock_list,freq="d1",field="close",num=10,df=False) |
stock_list:股票集
freq:数据的频度,可以为d1,h1,m1
field:close open high low volume volume_money
num:获取数据的数量
df:是否返回DataFrame格式的数据,默认为False
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def init(context): context.s1="sha-600000" sma12_factor=SMAFactor(12,"close") sma30_factor=SMAFactor(30,"close") reg_factor("sma12",sma12_factor) reg_factor("sma30",sma30_factor) schedule_function(my_func,DateRule.every_day(),TimeRule.once_per_day()) def my_func(context,data): stock=context.s1 ma12=factor_output("sma12",context.s1)["sma12"] ma30=factor_output("sma30",context.s1)["sma30"] if ma12>ma30: order(stock,1000) elif ma12 < ma30 and context.portfolio.positions[stock].amount > 0: order_target_value(stock,0) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
def init(context): context.s1="sza-000001" sma_factor=SMAFactor(20,"close") reg_factor("sma20",sma_factor) schedule_function(my_func,DateRule.every_day(),TimeRule.once_per_day()) def my_func(context, data): s1 = context.s1 price200 = factor_output("sma20",context.s1)["sma20"] close=data.days_current([s1],"close")[s1] cash = context.portfolio.cash # 如果当前有余额,并且上一时间点价格低于200日均线平均价格*0.95,买入 if close < price200 * 0.95 : order_percent(s1, 12) # 记录这次买入 log.info("Buying %s" % (s1)) # 如果当前价格高于200日平均价格*1.05,并且目前有头寸,卖出 elif close > price200 * 1.05 and context.portfolio.positions.has_key(s1): # 全部卖出 order_target(s1, 0) # 记录这次卖出 log.info("Selling %s" % (s1)) # 绘制股票价格 record("close",close) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def init(context): context.stocks=[] context.stocks.extend(['sha-600000', 'sza-300207', 'sza-002030', 'sza-300033', 'sha-600677', 'sha-600340', 'sza-300024', 'sha-600650', 'sza-300133', 'sza-000002', 'sha-600703', 'sza-300275', 'sza-002280', 'sha-600887' ]) context.bench_mark="sha-601318" context.slippage=0.003 dmi=DMIFactor(10) reg_factor("dmi",dmi) def every_day(context,data): for s in context.stocks: pdi=factor_output("dmi",[s])["dmi_pdi"][s] mdi=factor_output("dmi",[s])["dmi_mdi"][s] adx=factor_output("dmi",[s])["dmi_adx"][s] adxr=factor_output("dmi",[s])["dmi_adxr"][s] pdi_prev=factor_output("dmi",[s],"d1",-2)["dmi_pdi"][s] if pdi>pdi_prev and pdi>32 and adx>adxr and (pdi-mdi)>20 and adx<40: order_percent(s,10) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def init(context): context.stocks=[] context.stocks.extend(['sha-600000', 'sza-300207', 'sza-002030', 'sza-300033', 'sha-600677', 'sha-600340', 'sza-300024', 'sha-600650', 'sza-300133', 'sza-000002', 'sha-600703', 'sza-300275', 'sza-002280', 'sha-600887' ]) #股票池加入股票 context.bench_mark="sha-601318" #设置基准股票为"sha-601318" context.slippage=0.003 #设置测试时交易产生的浮点 kdj=STOCHASTICFactor() reg_factor("kdj",kdj) def every_day(context,data): for stock in context.stocks: out=factor_output("kdj",stock) out_prev=factor_output("kdj",stock,"d1",-2) k=out["kdj_stochk"] d=out["kdj_stochd"] k_prev=out_prev["kdj_stochk"] d_prev=out_prev["kdj_stochd"] if k>d and k_prev<d_prev: order_percent(stock,12) if k<d and k_prev>d_prev: order_target(stock,0) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def init(context): context.bench_mark="shz-000001" context.stocks=find_by_group("all-stocks") sma_factor=SMAFactor(22,"close") max_factor=MAXFactor(22,"close") reg_factor("sma",sma_factor) reg_factor("max",max_factor) reg_expr("rate","sma/max") schedule_function(my_func,DateRule.every_day(),TimeRule.once_per_day()) def my_func(context, data): output = factor_output_df("rate",context.stocks) abc=output.sort(columns="rate").tail(5) log.info(abc) abc=output.sort(columns="rate").head(5) log.info(abc) rs=output[(output.rate<1)&(output.rate>0.95) ] record("size",rs.size ) |
1 2 3 4 5 6 7 8 9 10 11 12 |
def init(context): context.bench_mark="sha-600498" context.slippage=0.003 schedule_function(select_stocks,DateRule.month(5),TimeRule.market_open(10) ) def select_stocks(context,data): df = get_fundamentals("brief_roic").sort(['brief_roic'],ascending=False).head(5) for pos in context.portfolio.positions.keys(): order_target(pos,0) for stock in df.get("brief_roic").keys(): log.info("buying stock %s"% stock) order_percent(stock,20) |
镭矿提供一系列股票组、股票概念供查询
入口地址: http://www.raquant.com/dev/category
使用方法:
1 |
stocks=find_by_group("all-stocks") |
其中传入股票组名称或id均可。