量化双均线策略:(二)判断买入卖出信号
2018-01-28 16:47
363 查看
上篇已经介绍了data的获取,此篇介绍ma5与ma10的双均线策略具体实现。双均线策略是一个趋势策略,基本思路是金叉买入,死叉卖出,也就是当ma5向上穿过ma10时,则买入,向下穿过ma10时,则卖出。
主要实现在Strategy类中,输入的变量格式如下:code_list = ['002415', '002416', '000333'],init_cash = 100000,starttime = '2014-01-01',endtime = '2017-11-30',其他几个重要成员变量如下:cash为还剩余的现金;capital_market_value为持仓的市值,按每天的收盘价计算;limit_cash为每只股票分得的仓位,双均线策略中,codelist中的股票平分持仓;position_list为持仓的情况,类型为dict,股票的code为key,持仓的数量为value;data_range为一个回测的日期list,pd.period_range的freq参数选择为B,即工作日;benchmark赋值为sh,即上证指数,以便比对策略结果。
实际的回测定义在run_simulation函数中,主循环框架为按天循环,通过每天的开盘价判断是否买入或者卖出(先判断卖出信号,再判断买入信号,具体判断在后面介绍),如果卖出成功,那么将卖出的所得加入到cash变量,对应的position变量调整为0(这个策略为初级策略,都是在每只股票的额度内全买全卖,后续策略会加入仓位控制),并将操作记录下到trade变量中。买入的操作也是类似的。每天买卖判断完成后,再按收盘价计算下持仓的市值,记录到capital_market_value中,以便统计每天的涨跌,计算sharp比率等统计指标。
所有天数回测结束后,将结果记录到res_df中,该变量为pandas类型,以便分析结果。res_df中数据有每天capital_market_value,每天的涨跌幅,每天对应的benchmark的值(因为回测的date_range已经剔除了周末,节假日等情况会存在停市,故capital_market_value与benchmark的值均使用之前第一个值填充),benchmark采用先bfill,然后还可能存在最开头的值是空的情况,在ffill填充,而capital_market_value则是使用df[df['date']
<= date].tail(1)['close']获得。
benchmark与captial_market_value的取得具体如下。
最重要的判断买入卖出信号如下。有个小地方需要注意下,给定一个date日期,df = df[df['date'] <= date].tail(3),获取了三天的价格,即今天的价格,昨天的价格,前天的价格,通过前天与昨天的均线价格去判断买入卖出。这是因为每天的均线价格是收盘价的平均(包含当天),策略的思路是每天通过开盘价买入或者卖出,但是当天的均线价格需要等收盘才能得到,也就是当买入或者卖出时候,只能使用昨天与前天的均线价格,否则就使用了未来函数。
剩下的几个就比较简单了,判断持仓数量,计算交易手续费。
主要实现在Strategy类中,输入的变量格式如下:code_list = ['002415', '002416', '000333'],init_cash = 100000,starttime = '2014-01-01',endtime = '2017-11-30',其他几个重要成员变量如下:cash为还剩余的现金;capital_market_value为持仓的市值,按每天的收盘价计算;limit_cash为每只股票分得的仓位,双均线策略中,codelist中的股票平分持仓;position_list为持仓的情况,类型为dict,股票的code为key,持仓的数量为value;data_range为一个回测的日期list,pd.period_range的freq参数选择为B,即工作日;benchmark赋值为sh,即上证指数,以便比对策略结果。
#coding=utf-8 from trade import Trade from data_repository import DataRepository import tushare as ts import pandas as pd import numpy as np import math class Strategy(object): def __init__(self, code_list, init_cash, start_time, end_time): self.start_time = start_time self.end_time = end_time self.data_repository = DataRepository.get_instance(code_list, self.start_time, self.end_time) self.code_list = code_list self.benchmark_code = 'sh' self.init_cash = init_cash self.cash = init_cash self.limited_cash = init_cash/len(code_list) self.position_list = {} for code in self.code_list: self.position_list[code] = 0 #存储trade对象 self.trade = Trade() d = list(pd.period_range(start=start_time, end=end_time, freq='B')) self.date_range = list(map(str, d)) self.res_df = pd.DataFrame() self.res_df['date'] = self.date_range self.capital_market_value = []
实际的回测定义在run_simulation函数中,主循环框架为按天循环,通过每天的开盘价判断是否买入或者卖出(先判断卖出信号,再判断买入信号,具体判断在后面介绍),如果卖出成功,那么将卖出的所得加入到cash变量,对应的position变量调整为0(这个策略为初级策略,都是在每只股票的额度内全买全卖,后续策略会加入仓位控制),并将操作记录下到trade变量中。买入的操作也是类似的。每天买卖判断完成后,再按收盘价计算下持仓的市值,记录到capital_market_value中,以便统计每天的涨跌,计算sharp比率等统计指标。
所有天数回测结束后,将结果记录到res_df中,该变量为pandas类型,以便分析结果。res_df中数据有每天capital_market_value,每天的涨跌幅,每天对应的benchmark的值(因为回测的date_range已经剔除了周末,节假日等情况会存在停市,故capital_market_value与benchmark的值均使用之前第一个值填充),benchmark采用先bfill,然后还可能存在最开头的值是空的情况,在ffill填充,而capital_market_value则是使用df[df['date']
<= date].tail(1)['close']获得。
def run_simulation(self): #按天循环 for date in self.date_range: for code in self.code_list: sell_signal, sell_open_price = self.get_sell_signal(code, date) direction = -1 if sell_signal == 1: amount = self.get_sell_amount(code) if amount > 0: commission = self.cal_cost_function(sell_open_price, amount) #更改现金 self.cash += sell_open_price*amount self.cash -= commission #更改持仓 self.position_list[code] -= amount #加入trade记录 self.trade.add_trade(code, sell_open_price, amount, date, direction, commission) for code in self.code_list: buy_signal, buy_open_price = self.get_buy_signal(code, date) direction = 1 if buy_signal == 1: amount = self.get_buy_amount(code, buy_open_price) if amount > 0: commission = self.cal_cost_function(buy_open_price, amount) #更改现金 self.cash -= buy_open_price*amount self.cash -= commission #更改持仓 self.position_list[code] += amount #加入trade记录 self.trade.add_trade(code, buy_open_price, amount, date, direction, commission) #计算每天的市值 self.capital_market_value.append(self.get_market_value(date)) #所有天循环结束后,加入到res_df self.res_df['capital_market_value'] = pd.Series(self.capital_market_value) self.res_df['profolio_daily_return'] = round((self.res_df['capital_market_value']/\ self.res_df['capital_market_value'].shift(1)-1),4) self.res_df['benchmark'] = self.get_benchmark_index() self.res_df['benchmark'].fillna(method='bfill', inplace=True) self.res_df['benchmark'].fillna(method='ffill', inplace=True) self.res_df.to_csv('./datares.csv')
benchmark与captial_market_value的取得具体如下。
def get_benchmark_index(self): df = ts.get_k_data(self.benchmark_code, start=self.start_time, end=self.end_time) benchmark_list = [] for date in self.date_range: if df[df['date'] == date].empty: benchmark_list.append(np.nan) else: benchmark_list.append(float(df[df['date'] == date]['close'])) return benchmark_list #得到某天的持仓股票的市值,加上cash,一并返回 def get_market_value(self, date): market_value = 0 for code in self.position_list: df = self.data_repository.get_onecode_df(code) if self.position_list[code] != 0: close_price = df[df['date'] <= date].tail(1)['close'] market_value += self.position_list[code]*float(close_price) return round(market_value+self.cash, 2)
最重要的判断买入卖出信号如下。有个小地方需要注意下,给定一个date日期,df = df[df['date'] <= date].tail(3),获取了三天的价格,即今天的价格,昨天的价格,前天的价格,通过前天与昨天的均线价格去判断买入卖出。这是因为每天的均线价格是收盘价的平均(包含当天),策略的思路是每天通过开盘价买入或者卖出,但是当天的均线价格需要等收盘才能得到,也就是当买入或者卖出时候,只能使用昨天与前天的均线价格,否则就使用了未来函数。
def get_sell_signal(self, code, date): df = self.data_repository.get_onecode_df(code) sell_signal = 0 sell_open_price = 0 if df[df['date'] == date].empty: return sell_signal, sell_open_price df = df[df['date'] <= date].tail(3) if len(df) == 3 and df.iloc[0]['ma5'] > df.iloc[0]['ma10'] and df.iloc[1]['ma5'] < df.iloc[1]['ma10']: sell_signal = 1 sell_open_price = df.iloc[1]['open'] return sell_signal, sell_open_price #以后还要加入判断止盈的方法 def get_buy_signal(self, code, date): df = self.data_repository.get_onecode_df(code) buy_signal = 0 buy_open_price = 0 if df[df['date'] == date].empty: return buy_signal, buy_open_price df = df[df['date'] <= date].tail(3) if len(df) == 3 and 4000 df.iloc[0]['ma5'] < df.iloc[0]['ma10'] and df.iloc[1]['ma5'] > df.iloc[1]['ma10']: buy_signal = 1 buy_open_price = df.iloc[1]['open'] return buy_signal, buy_open_pric
剩下的几个就比较简单了,判断持仓数量,计算交易手续费。
def get_sell_amount(self, code): return self.position_list[code] def get_buy_amount(self, code, price): if self.position_list[code] == 0: amount = math.floor(self.limited_cash/(price*100))*100 return amount else: return 0 def cal_cost_function(self, price, amount): commission = price*amount*0.0003 #最低5元手续费 if commission > 5: return commission else: return 5
相关文章推荐
- 【量化小讲堂-Python&Pandas系列10】如何判断一个策略的好坏?(附代码)
- 量化进阶——量化交易策略之羊驼和均线策略
- 量化双均线策略:(一)通过tushare获取股票数据
- 【大数据部落】r语言多均线量化策略回测
- 1-3移动均线交叉策略2
- (转)量化策略:Ricequant迎新年50篇干货分享
- 数论练习2:L - 取(m堆)石子游戏(用SG值来判断如果先手赢,求先手第一步的策略)
- 量化多因子策略回测框架Backtest
- 如何根据市场特征判断绝佳买入点
- 【量化小讲堂-Python&Pandas系列14】逆天的反转策略在A 股实证
- 1-4移动均线交叉策略3
- 量化策略
- 双均线策略
- 操盘策略:判断强庄股的四个诀窍
- 【量化课堂】多头趋势回踩策略
- 抓取全网财经新闻,计算新闻相关股票的多空舆情,量化买入
- 量化交易 Alpha Algo 1. 简单的双均线策略
- 使用反射+策略模式代替项目中大量的switch case判断
- 转:量化策略的分类和市场容量
- 华尔街量化策略全线遭重创 “标杆”文艺复兴基金六月大跌