-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
EricWang
committed
Feb 11, 2017
1 parent
ac6e050
commit c6e211a
Showing
6 changed files
with
429 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# 可以自己import我们平台支持的第三方python模块,比如pandas、numpy等 | ||
import talib | ||
|
||
|
||
# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递 | ||
def init(context): | ||
# context内引入全局变量s1,存储目标合约信息 | ||
context.s1 = 'IF1606' | ||
|
||
# 使用MACD需要设置长短均线和macd平均线的参数 | ||
context.SHORTPERIOD = 12 | ||
context.LONGPERIOD = 26 | ||
context.SMOOTHPERIOD = 9 | ||
context.OBSERVATION = 50 | ||
|
||
#初始化时订阅合约行情。订阅之后的合约行情会在handle_bar中进行更新 | ||
subscribe(context.s1) | ||
|
||
|
||
# 你选择的期货数据更新将会触发此段逻辑,例如日线或分钟线更新 | ||
def handle_bar(context, bar_dict): | ||
# 开始编写你的主要的算法逻辑 | ||
# 获取历史收盘价序列,history_bars函数直接返回ndarray,方便之后的有关指标计算 | ||
prices = history_bars(context.s1, context.OBSERVATION, '1d', 'close') | ||
|
||
# 用Talib计算MACD取值,得到三个时间序列数组,分别为macd,signal 和 hist | ||
macd, signal, hist = talib.MACD(prices, context.SHORTPERIOD, | ||
context.LONGPERIOD, context.SMOOTHPERIOD) | ||
|
||
# macd 是长短均线的差值,signal是macd的均线,如果短均线从下往上突破长均线,为入场信号,进行买入开仓操作 | ||
if macd[-1] - signal[-1] > 0 and macd[-2] - signal[-2] < 0: | ||
sell_qty = context.portfolio.positions[context.s1].sell_quantity | ||
# 先判断当前卖方仓位,如果有,则进行平仓操作 | ||
if sell_qty > 0: | ||
buy_close(context.s1, 1) | ||
# 买入开仓 | ||
buy_open(context.s1, 1) | ||
|
||
if macd[-1] - signal[-1] < 0 and macd[-2] - signal[-2] > 0: | ||
buy_qty = context.portfolio.positions[context.s1].buy_quantity | ||
# 先判断当前买方仓位,如果有,则进行平仓操作 | ||
if buy_qty > 0: | ||
sell_close(context.s1, 1) | ||
# 卖出开仓 | ||
sell_open(context.s1, 1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import talib | ||
|
||
|
||
# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。 | ||
def init(context): | ||
context.s1 = "000001.XSHE" | ||
|
||
# 设置这个策略当中会用到的参数,在策略中可以随时调用,这个策略使用长短均线,我们在这里设定长线和短线的区间,在调试寻找最佳区间的时候只需要在这里进行数值改动 | ||
context.SHORTPERIOD = 20 | ||
context.LONGPERIOD = 120 | ||
|
||
|
||
# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新 | ||
def handle_bar(context, bar_dict): | ||
# 开始编写你的主要的算法逻辑 | ||
|
||
# bar_dict[order_book_id] 可以拿到某个证券的bar信息 | ||
# context.portfolio 可以拿到现在的投资组合状态信息 | ||
|
||
# 使用order_shares(id_or_ins, amount)方法进行落单 | ||
|
||
# TODO: 开始编写你的算法吧! | ||
|
||
# 因为策略需要用到均线,所以需要读取历史数据 | ||
prices = history_bars(context.s1, context.LONGPERIOD+1, '1d', 'close') | ||
|
||
# 使用talib计算长短两根均线,均线以array的格式表达 | ||
short_avg = talib.SMA(prices, context.SHORTPERIOD) | ||
long_avg = talib.SMA(prices, context.LONGPERIOD) | ||
|
||
plot("short avg", short_avg[-1]) | ||
plot("long avg", long_avg[-1]) | ||
|
||
# 计算现在portfolio中股票的仓位 | ||
cur_position = context.portfolio.positions[context.s1].quantity | ||
# 计算现在portfolio中的现金可以购买多少股票 | ||
shares = context.portfolio.cash/bar_dict[context.s1].close | ||
|
||
# 如果短均线从上往下跌破长均线,也就是在目前的bar短线平均值低于长线平均值,而上一个bar的短线平均值高于长线平均值 | ||
if short_avg[-1] - long_avg[-1] < 0 and short_avg[-2] - long_avg[-2] > 0 and cur_position > 0: | ||
# 进行清仓 | ||
order_target_value(context.s1, 0) | ||
|
||
# 如果短均线从下往上突破长均线,为入场信号 | ||
if short_avg[-1] - long_avg[-1] > 0 and short_avg[-2] - long_avg[-2] < 0: | ||
# 满仓入股 | ||
order_shares(context.s1, shares) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import talib | ||
|
||
|
||
# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。 | ||
def init(context): | ||
context.s1 = "000001.XSHE" | ||
|
||
# 使用MACD需要设置长短均线和macd平均线的参数 | ||
context.SHORTPERIOD = 12 | ||
context.LONGPERIOD = 26 | ||
context.SMOOTHPERIOD = 9 | ||
context.OBSERVATION = 100 | ||
|
||
|
||
# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新 | ||
def handle_bar(context, bar_dict): | ||
# 开始编写你的主要的算法逻辑 | ||
|
||
# bar_dict[order_book_id] 可以拿到某个证券的bar信息 | ||
# context.portfolio 可以拿到现在的投资组合状态信息 | ||
|
||
# 使用order_shares(id_or_ins, amount)方法进行落单 | ||
|
||
# TODO: 开始编写你的算法吧! | ||
|
||
# 读取历史数据,使用sma方式计算均线准确度和数据长度无关,但是在使用ema方式计算均线时建议将历史数据窗口适当放大,结果会更加准确 | ||
prices = history_bars(context.s1, context.OBSERVATION,'1d','close') | ||
|
||
# 用Talib计算MACD取值,得到三个时间序列数组,分别为macd, signal 和 hist | ||
macd, signal, hist = talib.MACD(prices, context.SHORTPERIOD, | ||
context.LONGPERIOD, context.SMOOTHPERIOD) | ||
|
||
plot("macd", macd[-1]) | ||
plot("macd signal", signal[-1]) | ||
|
||
# macd 是长短均线的差值,signal是macd的均线,使用macd策略有几种不同的方法,我们这里采用macd线突破signal线的判断方法 | ||
|
||
# 如果macd从上往下跌破macd_signal | ||
|
||
if macd[-1] - signal[-1] < 0 and macd[-2] - signal[-2] > 0: | ||
# 计算现在portfolio中股票的仓位 | ||
curPosition = context.portfolio.positions[context.s1].quantity | ||
#进行清仓 | ||
if curPosition > 0: | ||
order_target_value(context.s1, 0) | ||
|
||
# 如果短均线从下往上突破长均线,为入场信号 | ||
if macd[-1] - signal[-1] > 0 and macd[-2] - signal[-2] < 0: | ||
# 满仓入股 | ||
order_target_percent(context.s1, 1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import numpy as np | ||
|
||
|
||
# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。 | ||
def init(context): | ||
context.s1 = 'AG1612' | ||
context.s2 = 'AU1612' | ||
|
||
# 设置全局计数器 | ||
context.counter = 0 | ||
|
||
# 设置滚动窗口 | ||
context.window = 60 | ||
|
||
# 设置对冲手数,通过研究历史数据进行价格序列回归得到该值 | ||
context.ratio = 15 | ||
|
||
context.up_cross_up_limit = False | ||
context.down_cross_down_limit = False | ||
|
||
# 设置入场临界值 | ||
context.entry_score = 2 | ||
|
||
# 初始化时订阅合约行情。订阅之后的合约行情会在handle_bar中进行更新 | ||
subscribe([context.s1, context.s2]) | ||
|
||
|
||
# before_trading此函数会在每天交易开始前被调用,当天只会被调用一次 | ||
def before_trading(context): | ||
# 样例商品期货在回测区间内有夜盘交易,所以在每日开盘前将计数器清零 | ||
context.counter = 0 | ||
|
||
|
||
# 你选择的期货数据更新将会触发此段逻辑,例如日线或分钟线更新 | ||
def handle_bar(context, bar_dict): | ||
|
||
# 获取当前一对合约的仓位情况。如尚未有仓位,则对应持仓量都为0 | ||
position_a = context.portfolio.positions[context.s1] | ||
position_b = context.portfolio.positions[context.s2] | ||
|
||
context.counter += 1 | ||
# 当累积满一定数量的bar数据时候,进行交易逻辑的判断 | ||
if context.counter > context.window: | ||
|
||
# 获取当天历史分钟线价格队列 | ||
price_array_a = history_bars(context.s1, context.window, '1m', 'close') | ||
price_array_b = history_bars(context.s2, context.window, '1m', 'close') | ||
|
||
# 计算价差序列、其标准差、均值、上限、下限 | ||
spread_array = price_array_a - context.ratio * price_array_b | ||
std = np.std(spread_array) | ||
mean = np.mean(spread_array) | ||
up_limit = mean + context.entry_score * std | ||
down_limit = mean - context.entry_score * std | ||
|
||
# 获取当前bar对应合约的收盘价格并计算价差 | ||
price_a = bar_dict[context.s1].close | ||
price_b = bar_dict[context.s2].close | ||
spread = price_a - context.ratio * price_b | ||
|
||
# 如果价差低于预先计算得到的下限,则为建仓信号,'买入'价差合约 | ||
if spread <= down_limit and not context.down_cross_down_limit: | ||
# 可以通过logger打印日志 | ||
logger.info('spread: {}, mean: {}, down_limit: {}'.format(spread, mean, down_limit)) | ||
logger.info('创建买入价差中...') | ||
|
||
# 获取当前剩余的应建仓的数量 | ||
qty_a = 1 - position_a.buy_quantity | ||
qty_b = context.ratio - position_b.sell_quantity | ||
|
||
# 由于存在成交不超过下一bar成交量25%的限制,所以可能要通过多次发单成交才能够成功建仓 | ||
if qty_a > 0: | ||
buy_open(context.s1, qty_a) | ||
if qty_b > 0: | ||
sell_open(context.s2, qty_b) | ||
if qty_a == 0 and qty_b == 0: | ||
# 已成功建立价差的'多仓' | ||
context.down_cross_down_limit = True | ||
logger.info('买入价差仓位创建成功!') | ||
|
||
# 如果价差向上回归移动平均线,则为平仓信号 | ||
if spread >= mean and context.down_cross_down_limit: | ||
logger.info('spread: {}, mean: {}, down_limit: {}'.format(spread, mean, down_limit)) | ||
logger.info('对买入价差仓位进行平仓操作中...') | ||
|
||
# 由于存在成交不超过下一bar成交量25%的限制,所以可能要通过多次发单成交才能够成功建仓 | ||
qty_a = position_a.buy_quantity | ||
qty_b = position_b.sell_quantity | ||
if qty_a > 0: | ||
sell_close(context.s1, qty_a) | ||
if qty_b > 0: | ||
buy_close(context.s2, qty_b) | ||
if qty_a == 0 and qty_b == 0: | ||
context.down_cross_down_limit = False | ||
logger.info('买入价差仓位平仓成功!') | ||
|
||
# 如果价差高于预先计算得到的上限,则为建仓信号,'卖出'价差合约 | ||
if spread >= up_limit and not context.up_cross_up_limit: | ||
logger.info('spread: {}, mean: {}, up_limit: {}'.format(spread, mean, up_limit)) | ||
logger.info('创建卖出价差中...') | ||
qty_a = 1 - position_a.sell_quantity | ||
qty_b = context.ratio - position_b.buy_quantity | ||
if qty_a > 0: | ||
sell_open(context.s1, qty_a) | ||
if qty_b > 0: | ||
buy_open(context.s2, qty_b) | ||
if qty_a == 0 and qty_b == 0: | ||
context.up_cross_up_limit = True | ||
logger.info('卖出价差仓位创建成功') | ||
|
||
# 如果价差向下回归移动平均线,则为平仓信号 | ||
if spread < mean and context.up_cross_up_limit: | ||
logger.info('spread: {}, mean: {}, up_limit: {}'.format(spread, mean, up_limit)) | ||
logger.info('对卖出价差仓位进行平仓操作中...') | ||
qty_a = position_a.sell_quantity | ||
qty_b = position_b.buy_quantity | ||
if qty_a > 0: | ||
buy_close(context.s1, qty_a) | ||
if qty_b > 0: | ||
sell_close(context.s2, qty_b) | ||
if qty_a == 0 and qty_b == 0: | ||
context.up_cross_up_limit = False | ||
logger.info('卖出价差仓位平仓成功!') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import talib | ||
|
||
|
||
# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。 | ||
def init(context): | ||
|
||
# 选择我们感兴趣的股票 | ||
context.s1 = "000001.XSHE" | ||
context.s2 = "601988.XSHG" | ||
context.s3 = "000068.XSHE" | ||
context.stocks = [context.s1, context.s2, context.s3] | ||
|
||
context.TIME_PERIOD = 14 | ||
context.HIGH_RSI = 85 | ||
context.LOW_RSI = 30 | ||
context.ORDER_PERCENT = 0.3 | ||
|
||
|
||
# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新 | ||
def handle_bar(context, bar_dict): | ||
# 开始编写你的主要的算法逻辑 | ||
|
||
# bar_dict[order_book_id] 可以拿到某个证券的bar信息 | ||
# context.portfolio 可以拿到现在的投资组合状态信息 | ||
|
||
# 使用order_shares(id_or_ins, amount)方法进行落单 | ||
|
||
# TODO: 开始编写你的算法吧! | ||
|
||
# 对我们选中的股票集合进行loop,运算每一只股票的RSI数值 | ||
for stock in context.stocks: | ||
# 读取历史数据 | ||
prices = history_bars(stock, context.TIME_PERIOD+1, '1d', 'close') | ||
|
||
# 用Talib计算RSI值 | ||
rsi_data = talib.RSI(prices, timeperiod=context.TIME_PERIOD)[-1] | ||
|
||
cur_position = context.portfolio.positions[stock].quantity | ||
# 用剩余现金的30%来购买新的股票 | ||
target_available_cash = context.portfolio.cash * context.ORDER_PERCENT | ||
|
||
# 当RSI大于设置的上限阀值,清仓该股票 | ||
if rsi_data > context.HIGH_RSI and cur_position > 0: | ||
order_target_value(stock, 0) | ||
|
||
# 当RSI小于设置的下限阀值,用剩余cash的一定比例补仓该股 | ||
if rsi_data < context.LOW_RSI: | ||
logger.info("target available cash caled: " + str(target_available_cash)) | ||
# 如果剩余的现金不够一手 - 100shares,那么会被ricequant 的order management system reject掉 | ||
order_value(stock, target_available_cash) |
Oops, something went wrong.