代码拉取完成,页面将自动刷新
同步操作将从 欧文杰/new_platform 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
# coding=utf-8
__author__ = 'ChenQi'
from gaojieju import train # 测试用模块(高阶矩)
# from FutureHmm import train # 测试用模块(HMM)
# from anfis import train # 测试用模块(神经网络)
from matplotlib.pyplot import savefig
import matplotlib.pyplot
import numpy as np
import MySQLdb
import pandas
import datetime
import time
import ConfigParser
cf = None
# 读取配置文件
def read_conf():
global cf
cf = ConfigParser.ConfigParser()
# 读取配置文件
cf.read("test.conf")
# 调用函数,读取配置文件
read_conf()
# 自定义想要遍历的期货类型
dataType_list = eval(cf.get("sec_b","dataType_list"))
# 自定义想要调用的期货数据精度
data_granularity = cf.get("sec_b","data_granularity")
# 用来输出到文件中的list
performance_list = []
# performance_hit = []
# 是否自定义买入价格
self_define_order_price = eval(cf.get("sec_b","self_define_order_price"))
# 是否自定义卖出价格
self_define_sell_price = eval(cf.get("sec_b","self_define_sell_price"))
# 如果要跑期货策略,future_or_timing = 0
# 如果要测试择时效果,future_or_timing = 1
future_or_timing = cf.getint("sec_b","future_or_timing")
# 输入文件路径和文件名
path_file = cf.get("sec_b","path_file")
# 输出指标的文件路径和文件名
path_performance = cf.get("sec_b","path_performance")
# 图片保存路径
path_saving_picture = cf.get("sec_b","path_saving_picture")
# 是否进行止损操作
want_stop_loss = eval(cf.get("sec_b","want_stop_loss"))
# -----------------------------------------------------------------------
class Account(object) :
def __init__(self,dataType,stop_loss_point_multiple,monitor_threshold,stop_earning_point):
self.dataType = dataType # 当前期货类型
self.conn = eval(cf.get("sec_a","database_link")) # 统一的数据库链接
# -----------------------------------------------------------------------------------
self.account_init = None # 该种期货的合约乘数、最小交易份额、手续费等一系列特定指标的表
self.gap_dataframe = None # 取各品种期货的价差数据,生成一个DataFrame表,用来进行价差处理
self.gap_handle_getData() # 取数据,用来进行价差处理
self.contract_list2_index() # 调用函数,提取该种期货的合约乘数、最小交易份额、手续费等一系列特定指标
# -----------------------------------------------------------------------------------
# self.R = 0.15 # 保证金率(杠杆)
self.R = float(self.account_init.loc['%s'%(dataType)]['caution_money']) # 保证金率(杠杆)
self.slippage = cf.getint("sec_a","n_slippage") * float(self.account_init.loc['%s'%(dataType)]['min_change_price']) # 滑点
# self.contract_multiple = 300 # 合约乘数
self.contract_multiple = float(self.account_init.loc['%s'%(dataType)]['contract_multiple']) # 合约乘数
# ----------------------------------------------------------------------------------
# self.calculate_commission_charge() # 调用函数,用于计算手续费
# ------------------------------------------------------------------------------------
self.stop_loss_point = stop_loss_point_multiple * float(self.account_init.loc['%s'%(dataType)]['min_change_price']) # 止损点(n倍最小变动单位)
self.monitor_threshold = monitor_threshold * float(self.account_init.loc['%s'%(dataType)]['min_change_price']) # 监控阈值(n倍最小变动单位)
self.stop_earning_point = stop_earning_point * float(self.account_init.loc['%s'%(dataType)]['min_change_price']) # 止盈点(n倍最小变动单位)
# -------------------------------------------------------------------------------------
self.training = cf.getint("sec_a","training") # 训练周期,用于计算年化收益率中起始阶段应跳过的天数
self.testing = cf.getint("sec_a","testing") # 测试周期,即择时信号维持天数
self.capital_init = eval(cf.get("sec_a","capital_init")) # 初始资金
self.start = cf.get("sec_a","start") # 起始时间
self.end = cf.get("sec_a","end") # 结束时间
self.expendable_fund_rate = float(cf.get("sec_a","expendable_fund_rate")) # 可用资金率
# -------------------------------------------------------------------------------
self.capital = self.capital_init # 动态资金
self.df = None # 导出数据的表
self.df_min = None # 止损用的分钟数据表
self.date_signal = {} # 导出数据中涨跌信号的字典
self.date_order_price = {} # 导出数据中买入价格信号的字典
self.date_sell_price = {} # 导出数据中卖出价格信号的字典
self.dayCounter = 0 # 计算当前运行天数
self.minCounter = 0 # 计算当前运行分钟数
self.orderPrice = 0.0 # 期货买入价格
self.sellPrice = 0.0 #期货卖出价格
self.accumulateProfit = 0.0 # 累计收益总数
self.remain_capital = 0.0 # 买进期货后剩余的资金
self.order_num = 0 # 计算可买进的手数
self.current_time = None # 当前时间
self.signal = 0 # 策略算出的涨跌信号
self.presignal = 0 # 策略算出的上一个涨跌信号
self.earn = 0.0 # 赚(亏)的钱
self.dataType = dataType # 数据的类型
self.date_min_list = [] # 分钟数据日期去重后的list
self.trading_point = 0 # 前一个交易点的时间下标(用于做止损止盈和判断手续费是否跨日)
self.is_stop_loss = False # 判断当前周期内是否已经止损止盈过
# --------------------------------------------------------------------------------------
# 提取该种期货的合约乘数、最小交易份额、手续费等一系列特定指标
def contract_list2_index(self):
# 取contract_list2表中的各项指标,用来初始化Account
conn = self.conn
sql = "select * from %s"%("contract_list2")
self.account_init = pandas.read_sql(sql,conn,index_col = 'code')
# conn.close()
# 将期货类型名统一转换成小写
upper_to_lower_list = []
for i in range(len(self.account_init)):
upper_to_lower_list.append(self.account_init.index[i].lower())
self.account_init.index = upper_to_lower_list
# 计算当前应缴纳手续费数额,判断日内交易和跨日交易的
def calculate_commission_charge(self):
# 用self.trading_point和self.minCounter来判断交易是否跨日
# self.commissionChargeRate = -1.0 # 手续费比例
self.commissionCharge = -1.0 # 手续费
# 如果当前交易为日内交易时
if self.df.index[self.trading_point].day == self.df.index[self.minCounter].day :
# print "----------------------------日内交易------------------------------"
# 如果手续费是按比例结算的
if float(self.account_init.loc['%s'%(self.dataType)]['poundage_order']) < 0.01 \
or float(self.account_init.loc['%s'%(self.dataType)]['poundage_today_sell']) < 0.01:
# 手续费买入时比例
self.commissionChargeRate_order = float(self.account_init.loc['%s'%(self.dataType)]['poundage_order'])
# 手续费卖出时比例
self.commissionChargeRate_sell = float(self.account_init.loc['%s'%(self.dataType)]['poundage_today_sell'])
# 如果手续费是固定价格的
if float(self.account_init.loc['%s'%(self.dataType)]['poundage_order']) > 0.01 \
or float(self.account_init.loc['%s'%(self.dataType)]['poundage_today_sell']) >0.01:
# 手续费
self.commissionCharge = float(self.account_init.loc['%s'%(self.dataType)]['poundage_order']) + float(self.account_init.loc['%s'%(self.dataType)]['poundage_today_sell'])
# 如果当前交易为跨日交易
if self.df.index[self.trading_point].day != self.df.index[self.minCounter].day :
# print "----------------------------跨日交易------------------------------"
# 如果手续费是按比例结算的
if float(self.account_init.loc['%s'%(self.dataType)]['poundage_order']) < 0.01 \
or float(self.account_init.loc['%s'%(self.dataType)]['poundage_anotherDay_sell']) < 0.01:
# 手续费买入时比例
self.commissionChargeRate_order = float(self.account_init.loc['%s'%(self.dataType)]['poundage_order'])
# 手续费卖出时比例
self.commissionChargeRate_sell = float(self.account_init.loc['%s'%(self.dataType)]['poundage_anotherDay_sell'])
# 如果手续费是固定价格的
if float(self.account_init.loc['%s'%(self.dataType)]['poundage_order']) > 0.01 \
or float(self.account_init.loc['%s'%(self.dataType)]['poundage_anotherDay_sell']) > 0.01:
# 手续费
self.commissionCharge = float(self.account_init.loc['%s'%(self.dataType)]['poundage_order']) + float(self.account_init.loc['%s'%(self.dataType)]['poundage_anotherDay_sell'])
# 用于判断手续费的类型:大于等于0时,手续费为固定金额;小于0时,手续费按比例收取
self.commissionTypeJudge = self.commissionCharge
# 计算当前应缴纳手续费数额,日内交易专用
def calculate_commission_charge_one_day(self):
self.commissionChargeRate = -1.0 # 手续费比例
self.commissionCharge = -1.0 # 手续费
# 如果手续费是按比例结算的
if float(self.account_init.loc['%s'%(self.dataType)]['poundage_order']) < 0.01 or float(self.account_init.loc['%s'%(self.dataType)]['poundage_today_sell']) < 0.01:
# 手续费买入时比例
self.commissionChargeRate_order = float(self.account_init.loc['%s'%(self.dataType)]['poundage_order'])
# 手续费卖出时比例
self.commissionChargeRate_sell = float(self.account_init.loc['%s'%(self.dataType)]['poundage_today_sell'])
# 如果手续费是固定价格的
if float(self.account_init.loc['%s'%(self.dataType)]['poundage_order']) > 0.01 \
or float(self.account_init.loc['%s'%(self.dataType)]['poundage_today_sell']) >0.01\
or float(self.account_init.loc['%s'%(self.dataType)]['poundage_anotherDay_sell']) > 0.01:
# 手续费
self.commissionCharge = float(self.account_init.loc['%s'%(self.dataType)]['poundage_order']) + float(self.account_init.loc['%s'%(self.dataType)]['poundage_today_sell'])
# 用于判断手续费的类型:大于等于0时,手续费为固定金额;小于0时,手续费按比例收取
self.commissionTypeJudge = self.commissionCharge
# 将时间由String类型转化为Date类型
def str2date(self,timeStr):
timeDate = datetime.datetime.strptime(timeStr[0:10], '%Y-%m-%d').date()
return timeDate
# 将时间由String类型转化为Datetime类型
def str2datetime(self,timeStr):
timeDate = datetime.datetime.strptime(timeStr, '%Y-%m-%d %H:%M:%S')
return timeDate
# 将时间由Datetime类型转化成String类型,精度低的
def datetime2str(self,strTime):
strDate = strTime.strftime('%Y-%m-%d')
return strDate
# 将时间由Datetime类型转化成String类型,精度高的
def datetime2string(self,strTime):
strDate = strTime.strftime('%Y-%m-%d %H:%M:%S')
return strDate
# 取数据
def getData(self):
# 处理,添加后缀
dataType_temp = "%s_%s"%(self.dataType,data_granularity)
# 如果是用来跑期货策略
if future_or_timing==0:
# 期货数据类型
conn = self.conn
sql = "select * from %s"%(dataType_temp)
# 如果是用来进行择时效果测试
if future_or_timing==1:
# 如果按照任意时间一手来进行比较
if eval(cf.get("sec_b","if_one_hand"))==True :
# 期货数据类型
conn = self.conn
sql = "select * from %s"%(dataType_temp)
# 股票择时效果测试
if eval(cf.get("sec_b","if_one_hand"))==False :
# 数据类型
conn = self.conn
sql = "select * from %s"%("hushen300_IF00")
self.df = pandas.read_sql(sql,conn,index_col = 'date')
# conn.close()
# 切成当前设置日期内的表
# 将开始时间和结束时间由String类型转化成Datetime类型
start_time = self.str2datetime(self.start)
end_time = self.str2datetime(self.end)
# 如果自定义的开始时间小于数据库中有的开始时间,则自动切到数据库起始时间
if self.df.index[0] > start_time :
start_time = self.df.index[0]
# 如果自定义的结束时间大于数据库中的结束时间,则自动切到数据库结束时间
if self.df.index[len(self.df)-1] < end_time :
end_time = self.df.index[len(self.df)-1]
end_time=end_time+datetime.timedelta(days=1)
# 按自定义起始和结束时间切表
self.df = self.df[(self.df.index>=start_time)&(self.df.index<=end_time)]
# 分钟数据日期去重处理
def data_min_date_list(self):
# 建立一个date的集合,用于去重
date_set = set()
for i in range(len(self.df)):
strDate = self.datetime2str(self.df.index[i])
date_set.add(strDate)
# 将集合转化为list形式,以便能通过下标访问
self.date_min_list = list(date_set)
self.date_min_list.sort()
# datetime时间拼接处理,日期不变,将时间换成自定义时间
def datetime_catch(self,my_datetime,my_time_str):
my_datetime = self.datetime2str(my_datetime)
my_datetime = my_datetime+' '+my_time_str
my_datetime = self.str2datetime(my_datetime)
return my_datetime
# 增加属性
def appendAttribute(self):
# 增加信号列,预测涨为1,预测跌为-1,默认为0
self.df['signal'] = pandas.Series(0, index = self.df.index)
# 添加买入价格列
self.df['order'] = pandas.Series(0.0 , index = self.df.index)
# 添加卖出价格列
self.df['sell'] = pandas.Series(0.0 , index = self.df.index)
# 从signal.txt中取涨跌信号数据
# 输入文件中没有买入价格和卖出价格
if ((self_define_order_price == False) and (self_define_sell_price == False)):
temp = np.loadtxt(path_file,delimiter=",", usecols=[0,1],dtype=str)
for i in range(len(temp)):
self.date_signal[temp[i][0]] = int(temp[i][1])
for i in self.df.index:
self.df.loc[i,['signal']] = self.date_signal[str(i)]
# 输入文件中有买入价格,没有卖出价格
if ((self_define_order_price == True) and (self_define_sell_price == False)):
temp = np.loadtxt(path_file,delimiter=",", usecols=[0,1,2],dtype=str)
for i in range(len(temp)):
self.date_signal[temp[i][0]] = int(temp[i][1])
self.date_order_price[temp[i][0]] = float(temp[i][2])
for i in self.df.index:
self.df.loc[i,['signal']] = self.date_signal[str(i)]
self.df.loc[i,['order']] = self.date_order_price[str(i)]
# 输入文件中没有买入价格,有卖出价格
if ((self_define_order_price == False) and (self_define_sell_price == True)):
temp = np.loadtxt(path_file,delimiter=",", usecols=[0,1,2],dtype=str)
for i in range(len(temp)):
self.date_signal[temp[i][0]] = int(temp[i][1])
self.date_sell_price[temp[i][0]] = float(temp[i][3])
for i in self.df.index:
self.df.loc[i,['signal']] = self.date_signal[str(i)]
self.df.loc[i,['sell']] = self.date_sell_price[str(i)]
# 输入文件中有买入价格和卖出价格
if ((self_define_order_price == True) and (self_define_sell_price == True)):
temp = np.loadtxt(path_file,delimiter=",", usecols=[0,1,2,3],dtype=str)
for i in range(len(temp)):
self.date_signal[temp[i][0]] = int(temp[i][1])
self.date_order_price[temp[i][0]] = float(temp[i][2])
self.date_sell_price[temp[i][0]] = float(temp[i][3])
for i in self.df.index:
self.df.loc[i,['signal']] = self.date_signal[str(i)]
self.df.loc[i,['order']] = self.date_order_price[str(i)]
self.df.loc[i,['sell']] = self.date_sell_price[str(i)]
# 增加每日动态资产列
self.df['capital'] = pandas.Series(self.capital, index = self.df.index)
# 增加命中信号列,命中为1,未命中为-1,默认为0
self.df['hit'] = pandas.Series(0, index = self.df.index)
# 买进的手数列,初始值为0
self.df['order_num'] = pandas.Series(0, index = self.df.index)
# 盈利(亏损)的点数
self.df['point_num'] = pandas.Series(0.0, index = self.df.index)
# 买进期货
def order(self):
# 如果是用来跑期货策略
if future_or_timing==0:
# 计算可买进的手数,总动态资金的30%用做购买期货
self.order_num = int((self.capital*self.expendable_fund_rate)/(self.orderPrice*self.R*self.contract_multiple))
# 如果是用来进行择时效果测试
if future_or_timing==1:
# 买1手,用来进行择时效果的测试
self.order_num = 1
print "当前手数:",self.order_num
# # 如果手数大于25,取25,防爆仓
# if self.order_num > 25 :
# self.order_num = 25
# 计算买进后剩余的资金,包括剩余的70%和30%中剩下的部分
self.remain_capital = self.capital - self.order_num*(self.orderPrice*self.R*self.contract_multiple)
# 取数据,用来进行价差处理
def gap_handle_getData(self):
# 取deliveryinfo表中的所有数据,用来进行价差处理
conn = self.conn
sql = "select * from %s where code = '%s'"%("deliveryinfo",self.dataType)
self.gap_dataframe = pandas.read_sql(sql,conn,index_col = 'code')
# conn.close()
# 将期货类型名统一转换成小写
upper_to_lower_list = []
for i in range(len(self.gap_dataframe)):
upper_to_lower_list.append(self.gap_dataframe.index[i].lower())
self.gap_dataframe.index = upper_to_lower_list
# print self.gap_dataframe
# 卖出期货,天数据
def sell(self):
self.calculate_commission_charge_one_day()
# 如果是用来跑期货策略
if future_or_timing==0:
# 计算手续费,判断条件:手续费self.commissionTypeJudge大于等于0时,手续费按照具体金额结算
if self.commissionTypeJudge >= 0 :
# print "----------------commissionCharge1-----------------"
# 计算动态资产
self.capital = self.capital - self.commissionCharge + self.earn - (self.slippage*self.contract_multiple*self.order_num)
# print self.commissionCharge
# 计算手续费,判断条件:手续费self.commissionTypeJudge小于0时,手续费按照比例结算
if self.commissionTypeJudge < 0 :
# print "----------------commissionCharge2-----------------"
commissionCharge_temp = (self.orderPrice*self.commissionChargeRate_order+self.sellPrice*self.commissionChargeRate_sell) * self.R * self.contract_multiple * self.order_num
# 计算动态资产
self.capital = self.capital - commissionCharge_temp + self.earn - (self.slippage*self.contract_multiple*self.order_num)
# 如果是用来进行择时效果测试
if future_or_timing==1:
self.capital = self.capital + self.earn
# ==========================================================================
# 进行价差处理,直接在计算后的动态资产上加减价差值
# self.gap_handle_getData()
# 方法:由大到小遍历,直到找到当前时间点self.dayCounter第一个大于的gap时间点j
current_gap = 0.0
for j in range(len(self.gap_dataframe)-1,-1,-1):
# 当前时间点为gap时间点
if self.df.index[self.dayCounter]==self.gap_dataframe['date'][j] :
# 计算当前时间点的数据应该平移的数值
# 用从当前选出的gap时间点j往前的所有周期内的gap时间点的价差进行当前价差的计算
print "---------------------------运行-------------------------------"
current_gap = self.gap_dataframe['gap'][j]
break
# 价差带来的金额差值
price_gap = (current_gap)*self.df['order_num'][self.dayCounter]*self.contract_multiple
print "current_gap : ",current_gap
print "order_num : ",self.df['order_num'][self.dayCounter]
print "price_gap : ",price_gap
# 涨跌方向是否与gap方向一致:
# 如果一致,则是赚多了,要减去
# 如果不一致,则是亏多了,要加上
if self.df['signal'][self.dayCounter]*current_gap>0 :
print "如果一致,则是赚多了,要减去"
# 实际动态资产为
self.capital -= price_gap
if self.df['signal'][self.dayCounter]*current_gap<0 :
print "如果不一致,则是亏多了,要加上"
# 实际动态资产为
self.capital += price_gap
# ==========================================================================
# 记录每天动态资产变化情况
self.df['capital'][self.dayCounter] = self.capital
# 卖出期货,分钟数据
def sell_min(self):
# 调用函数,用于计算手续费
self.calculate_commission_charge()
# 计算手续费,判断条件:手续费self.commissionTypeJudge大于等于0时,手续费按照具体金额结算
if self.commissionTypeJudge >= 0 :
# print "----------------commissionCharge1-----------------"
# 计算动态资产
self.capital = self.capital - self.commissionCharge + self.earn - (self.slippage*self.contract_multiple*self.order_num)
# print self.commissionCharge
# 计算手续费,判断条件:手续费self.commissionTypeJudge小于0时,手续费按照比例结算
if self.commissionTypeJudge < 0 :
# print "----------------commissionCharge2-----------------"
commissionCharge_temp = (self.orderPrice*self.commissionChargeRate_order+self.sellPrice*self.commissionChargeRate_sell) * self.R * self.contract_multiple * self.order_num
# 计算动态资产
self.capital = self.capital - commissionCharge_temp + self.earn - (self.slippage*self.contract_multiple*self.order_num)
# ==========================================================================
# 进行价差处理,直接在计算后的动态资产上加减价差值
# self.gap_handle_getData()
# 寻找两次交易时间点间的gap,并计算总gap的大小
current_gap = 0.0
for j in range(len(self.gap_dataframe)-1,-1,-1):
if self.datetime_catch(self.gap_dataframe['date'][j],"15:15:00")>self.df.index[self.trading_point]\
and self.datetime_catch(self.gap_dataframe['date'][j],"15:15:00")<self.df.index[self.minCounter] :
# 计算当前时间点的数据应该平移的数值
# 用从当前选出的gap时间点j往前的所有周期内的gap时间点的价差进行当前价差的计算
print "---------------------------运行-------------------------------"
current_gap += self.gap_dataframe['gap'][j]
break
# 价差带来的金额差值
price_gap = (current_gap)*self.df['order_num'][self.minCounter-1]*self.contract_multiple
print "current_gap : ",current_gap
print "order_num : ",self.df['order_num'][self.minCounter-1]
print "price_gap : ",price_gap
# 涨跌方向是否与gap方向一致:
# 如果一致,则是赚多了,要减去
# 如果不一致,则是亏多了,要加上
if self.df['signal'][self.minCounter-1]*current_gap>0 :
print "如果一致,则是赚多了,要减去"
# 实际动态资产为
self.capital -= price_gap
if self.df['signal'][self.minCounter-1]*current_gap<0 :
print "如果不一致,则是亏多了,要加上"
# 实际动态资产为
self.capital += price_gap
# ==========================================================================
# 止损止盈
# 输入的参数:开始时间、结束时间、期间的涨跌信号、期间的持有手数
def stop_loss(self,start,end,signal,order_num):
# 最高价、最低价止损(粗略版)
# # 择时信号看涨时,open-low大于10点,则止损
# if self.signal > 0 :
# if (self.df['open'][self.dayCounter] - self.df['low'][self.dayCounter]) > 10 :
# self.earn = -10 * self.order_num * self.contract_multiple
# print '------------------------stop---------------------------'
# # 择时信号看跌时,high-open大于10点,则止损
# if self.signal < 0 :
# if (self.df['high'][self.dayCounter] - self.df['open'][self.dayCounter]) > 10 :
# self.earn = -10 * self.order_num * self.contract_multiple
# print '------------------------stop---------------------------'
#################################################################
# 最高价、最低价止损(精确版)
# ==========================================================================
# 防止发生由于价差而导致的止损止盈
# 取出当前start~end内的所有gap点
current_gap_datetime = []
current_gap_date = []
for i in range(len(self.gap_dataframe)):
if self.datetime_catch(self.gap_dataframe['date'][i],"15:15:00")>=start\
and self.datetime_catch(self.gap_dataframe['date'][i],"15:15:00")<end :
current_gap_datetime.append(self.datetime_catch(self.gap_dataframe['date'][i],"15:15:00"))
current_gap_date.append(self.gap_dataframe['date'][i])
# ==========================================================================
# 将datetime类型转化为string类型
start = self.datetime2string(start)
end = self.datetime2string(end)
print start
print end
# 处理,添加后缀
dataType_temp = "%s_m1"%(self.dataType)
# 取分钟数据进行止损(止盈)
conn = self.conn
sql = "select * from %s where date between '%s' and '%s'"%(dataType_temp,start,end)
self.df_min = pandas.read_sql(sql,conn,index_col = 'date')
# conn.close()
# ==========================================================================
# 为了兼容部分期货类型夜盘的情况,gap日期15:00后的数据都进行价差处理
for i in range(len(self.df_min)):
# 判断当前时间点属于哪两个gap时间点之间
# 方法:由大到小遍历,直到找到当前时间点i第一个大于的gap时间点j
for j in range(len(current_gap_datetime)-1,-1,-1):
if self.df_min.index[i]>current_gap_datetime[j] :
# 计算当前时间点的数据应该平移的数值
# 用从当前选出的gap时间点j往前的所有周期内的gap时间点的价差进行当前价差的计算
current_gap = 0.0
for k in range(j+1):
current_gap += self.gap_dataframe[(self.gap_dataframe['date']==current_gap_date[k])]['gap'][0]
# 将所有self.df_min中的数据向上或向下平移current_gap个单位
self.df_min.loc[self.df_min.index[i],'open'] += current_gap
self.df_min.loc[self.df_min.index[i],'high'] += current_gap
self.df_min.loc[self.df_min.index[i],'low'] += current_gap
self.df_min.loc[self.df_min.index[i],'close'] += current_gap
print "----------------价差处理stop_loss----------------"
break
# ==========================================================================
# 当天的初始价格(暂定为开盘价)
current_day_init_price = self.df['open'][start]
# 当前的累计收益
cumulated_earning = 0.0
# 是否开始监控,默认为False
isMonitor = False
# 当前已遍历数据的最大累计收益
current_max_earning = 0.0
# 涨跌信号大于0时的情况
if signal > 0 :
# 遍历每一个分钟数据
for data_min in range(len(self.df_min)) :
cumulated_earning = self.df_min[data_min:data_min+1]['close'][0] - current_day_init_price
# 止损,若累计收益小于止损点,则止损
if cumulated_earning <= (-self.stop_loss_point) :
self.earn = -self.stop_loss_point * order_num * self.contract_multiple
print '------------------------stop1---------------------------'
# 止损(止盈)损失(赚取)的点数
self.point_num = -self.stop_loss_point
# 止损后,is_stop_loss变为True
self.is_stop_loss = True
break
# 止盈,累计收益大于设定阈值,开始监控
if cumulated_earning > self.monitor_threshold :
isMonitor = True
# 止盈,累计收益回撤大于止盈点,则止盈
if isMonitor == True :
# 更新当前最大累计收益
if cumulated_earning > current_max_earning :
current_max_earning = cumulated_earning
# 如果累计收益小于(最大累计收益 - 止盈点数),则止盈
if cumulated_earning < (current_max_earning - self.stop_earning_point) :
self.earn = (current_max_earning - self.stop_earning_point) * order_num * self.contract_multiple
print '------------------------stop2---------------------------'
# 止损(止盈)损失(赚取)的点数
self.point_num = current_max_earning - self.stop_earning_point
# 止损后,is_stop_loss变为True
self.is_stop_loss = True
break
# 涨跌信号小于0时的情况
if signal < 0 :
# 遍历每一个分钟数据
for data_min in range(len(self.df_min)) :
cumulated_earning = current_day_init_price - self.df_min[data_min:data_min+1]['close'][0]
# 止损,若累计收益小于止损点,则止损
if cumulated_earning <= (-self.stop_loss_point) :
self.earn = -self.stop_loss_point * order_num * self.contract_multiple
print '------------------------stop3---------------------------'
# 止损(止盈)损失(赚取)的点数
self.point_num = -self.stop_loss_point
# 止损后,is_stop_loss变为True
self.is_stop_loss = True
break
# 止盈,累计收益大于设定阈值,开始监控
if cumulated_earning > self.monitor_threshold :
isMonitor = True
# 止盈,累计收益回撤大于止盈点,则止盈
if isMonitor == True :
# 更新当前最大累计收益
if cumulated_earning > current_max_earning :
current_max_earning = cumulated_earning
# 如果累计收益小于(最大累计收益 - 止盈点数),则止盈
if cumulated_earning < (current_max_earning - self.stop_earning_point) :
self.earn = (current_max_earning - self.stop_earning_point) * order_num * self.contract_multiple
print '------------------------stop4---------------------------'
# 止损(止盈)损失(赚取)的点数
self.point_num = current_max_earning - self.stop_earning_point
# 止损后,is_stop_loss变为True
self.is_stop_loss = True
break
# =========================================================
# 进行价差处理:
# (1)训练周期分两种情况:
# a.以训练周期内第一段数据段为基准,将价差段后的数据向上或向下平移
# b.保留裸数据,不上下平移
# (2)训练周期情况:
# 统一根据评估周期和训练周期内的第一段数据段为基准,将数据上下平移
# =========================================================
# 第一种情况的方法:训练周期和测试周期的数据都进行价差处理
def gap_handle(self,gap_dataframe,training_dayCounter,testing_dayCounter,df_strategy,dayCounter_strategy):
# 不是最后一轮时的价差处理方法
if dayCounter_strategy != len(self.df)-1 :
# 取出当前训练测试周期内的所有gap点
current_gap_datetime = []
for i in range(len(gap_dataframe)):
if self.datetime_catch(gap_dataframe['date'][i],"15:15:00")>=self.df.index[training_dayCounter]\
and self.datetime_catch(gap_dataframe['date'][i],"15:15:00")<self.df.index[testing_dayCounter+self.testing] :
current_gap_datetime.append(gap_dataframe['date'][i])
# 为了兼容部分期货类型夜盘的情况,gap日期15:00后的数据都进行价差处理
for i in range(self.training+self.testing):
# 判断当前时间点属于哪两个gap时间点之间
# 方法:由大到小遍历,直到找到当前时间点i第一个大于的gap时间点j
for j in range(len(current_gap_datetime)-1,-1,-1):
if self.df.index[training_dayCounter+i]>current_gap_datetime[j] :
# print "----------------%s----------------"%self.df.index[training_dayCounter+i]
# 计算当前时间点的数据应该平移的数值
# 用从当前选出的gap时间点j往前的所有周期内的gap时间点的价差进行当前价差的计算
current_gap = 0.0
for k in range(j+1):
current_gap += gap_dataframe[(gap_dataframe['date']==current_gap_datetime[k])]['gap'][0]
# print df_strategy.iloc[training_dayCounter+i]
# 将所有df_strategy中的数据向上或向下平移current_gap个单位
df_strategy.loc[df_strategy.index[training_dayCounter+i],'open'] += current_gap
df_strategy.loc[df_strategy.index[training_dayCounter+i],'high'] += current_gap
df_strategy.loc[df_strategy.index[training_dayCounter+i],'low'] += current_gap
df_strategy.loc[df_strategy.index[training_dayCounter+i],'close'] += current_gap
# print df_strategy.iloc[training_dayCounter+i]
print "----------------价差处理1----------------"
break
# 最后一轮时的价差处理方法
# 如果存在完整的训练周期和不完整的测试周期,则处理最后一轮
if dayCounter_strategy == len(self.df)-1 :
# 取出当前全部训练周期和部分测试周期内的所有gap点
current_gap_datetime = []
for i in range(len(gap_dataframe)):
if self.datetime_catch(gap_dataframe['date'][i],"15:15:00")>=self.df.index[training_dayCounter]\
and self.datetime_catch(gap_dataframe['date'][i],"15:15:00")<self.df.index[dayCounter_strategy] :
current_gap_datetime.append(gap_dataframe['date'][i])
# 为了兼容部分期货类型夜盘的情况,gap日期15:00后的数据都进行价差处理
for i in range(dayCounter_strategy-training_dayCounter):
# 判断当前时间点属于哪两个gap时间点之间
# 方法:由大到小遍历,直到找到当前时间点i第一个大于的gap时间点j
for j in range(len(current_gap_datetime)-1,-1,-1):
if self.df.index[training_dayCounter+i]>current_gap_datetime[j] :
# print "----------------%s----------------"%self.df.index[training_dayCounter+i]
# 计算当前时间点的数据应该平移的数值
# 用从当前选出的gap时间点j往前的所有周期内的gap时间点的价差进行当前价差的计算
current_gap = 0.0
for k in range(j+1):
current_gap += gap_dataframe[(gap_dataframe['date']==current_gap_datetime[k])]['gap'][0]
# print df_strategy.iloc[training_dayCounter+i]
# 将所有df_strategy中的数据向上或向下平移current_gap个单位
df_strategy.loc[df_strategy.index[training_dayCounter+i],'open'] += current_gap
df_strategy.loc[df_strategy.index[training_dayCounter+i],'high'] += current_gap
df_strategy.loc[df_strategy.index[training_dayCounter+i],'low'] += current_gap
df_strategy.loc[df_strategy.index[training_dayCounter+i],'close'] += current_gap
# print df_strategy.iloc[training_dayCounter+i]
print "----------------价差处理1----------------"
break
return df_strategy
# 第二种情况的方法:训练周期不进行价差处理,只有测试周期进行价差处理
def gap_handle_rawTrain(self,gap_dataframe,training_dayCounter,testing_dayCounter,df_strategy,dayCounter_strategy):
# 不是最后一轮时的价差处理方法
if dayCounter_strategy != len(self.df)-1 :
# 取出当前训练测试周期内的所有gap点
current_gap_datetime = []
for i in range(len(gap_dataframe)):
if self.datetime_catch(gap_dataframe['date'][i],"15:15:00")>=self.df.index[testing_dayCounter]\
and self.datetime_catch(gap_dataframe['date'][i],"15:15:00")<self.df.index[testing_dayCounter+self.testing] :
current_gap_datetime.append(gap_dataframe['date'][i])
# 为了兼容部分期货类型夜盘的情况,gap日期15:00后的数据都进行价差处理
for i in range(self.testing):
# 判断当前时间点属于哪两个gap时间点之间
# 方法:由大到小遍历,直到找到当前时间点i第一个大于的gap时间点j
for j in range(len(current_gap_datetime)-1,-1,-1):
if self.df.index[testing_dayCounter+i]>current_gap_datetime[j] :
# print "----------------%s----------------"%self.df.index[testing_dayCounter+i]
# 计算当前时间点的数据应该平移的数值
# 用从当前选出的gap时间点j往前的所有周期内的gap时间点的价差进行当前价差的计算
current_gap = 0.0
for k in range(j+1):
current_gap += gap_dataframe[(gap_dataframe['date']==current_gap_datetime[k])]['gap'][0]
# print df_strategy.iloc[testing_dayCounter+i]
# 将所有df_strategy中的数据向上或向下平移current_gap个单位
df_strategy.loc[df_strategy.index[testing_dayCounter+i],'open'] += current_gap
df_strategy.loc[df_strategy.index[testing_dayCounter+i],'high'] += current_gap
df_strategy.loc[df_strategy.index[testing_dayCounter+i],'low'] += current_gap
df_strategy.loc[df_strategy.index[testing_dayCounter+i],'close'] += current_gap
# print df_strategy.iloc[testing_dayCounter+i]
print "----------------价差处理2----------------"
break
# 最后一轮时的价差处理方法
# 如果存在完整的训练周期和不完整的测试周期,则处理最后一轮
if dayCounter_strategy == len(self.df)-1 :
# 取出当前全部训练周期和部分测试周期内的所有gap点
current_gap_datetime = []
for i in range(len(gap_dataframe)):
if self.datetime_catch(gap_dataframe['date'][i],"15:15:00")>=self.df.index[testing_dayCounter]\
and self.datetime_catch(gap_dataframe['date'][i],"15:15:00")<self.df.index[dayCounter_strategy] :
current_gap_datetime.append(gap_dataframe['date'][i])
# 为了兼容部分期货类型夜盘的情况,gap日期15:00后的数据都进行价差处理
for i in range(dayCounter_strategy-testing_dayCounter):
# 判断当前时间点属于哪两个gap时间点之间
# 方法:由大到小遍历,直到找到当前时间点i第一个大于的gap时间点j
for j in range(len(current_gap_datetime)-1,-1,-1):
if self.df.index[testing_dayCounter+i]>current_gap_datetime[j] :
# print "----------------%s----------------"%self.df.index[testing_dayCounter+i]
# 计算当前时间点的数据应该平移的数值
# 用从当前选出的gap时间点j往前的所有周期内的gap时间点的价差进行当前价差的计算
current_gap = 0.0
for k in range(j+1):
current_gap += gap_dataframe[(gap_dataframe['date']==current_gap_datetime[k])]['gap'][0]
# print df_strategy.iloc[testing_dayCounter+i]
# 将所有df_strategy中的数据向上或向下平移current_gap个单位
df_strategy.loc[df_strategy.index[testing_dayCounter+i],'open'] += current_gap
df_strategy.loc[df_strategy.index[testing_dayCounter+i],'high'] += current_gap
df_strategy.loc[df_strategy.index[testing_dayCounter+i],'low'] += current_gap
df_strategy.loc[df_strategy.index[testing_dayCounter+i],'close'] += current_gap
# print df_strategy.iloc[testing_dayCounter+i]
print "----------------价差处理2----------------"
break
return df_strategy
# 统一的平台策略接口,用来调度策略,生成涨跌信号文件的
def handle_strategy(self):
# # 调用函数,提取不同期货类型的价差数据
# self.gap_handle_getData()
# 给出所有的索引列,即交易日列
df_strategy_date = self.df.index
# 当前为第几轮的训练测试周期
training_testing_round = 0
# 遍历每一天
for dayCounter_strategy in range(len(self.df)):
# 当前不是最后一个循环周期时进行的策略,将当前日期之前的数据传给策略
if dayCounter_strategy != len(self.df)-1:
# 当前时间能取到的所有数据,即当前日期之前的所有数据
df_strategy = self.df[self.df.index<self.df.index[dayCounter_strategy]]
# 每个测试点调用一次策略
if (dayCounter_strategy - self.training)%self.testing==0 \
and (dayCounter_strategy - self.training - self.testing) >= 0 :
print self.df.index[dayCounter_strategy - self.training - self.testing]
# 训练测试测试周期轮数加一
training_testing_round += 1
# 计算当前数据训练周期应该开始的点是第几天
training_dayCounter = self.testing*(training_testing_round-1)
# 计算当前数据测试周期应该开始的点是第几天
testing_dayCounter = self.testing*(training_testing_round-1)+self.training
# 根据配置文件中设置,来判断训练周期是否进行价差处理
if eval(cf.get("sec_e","is_training_rawData"))==True :
# 调用gap_handle_rawTrain函数来进行价差处理
df_strategy = self.gap_handle_rawTrain(self.gap_dataframe,training_dayCounter\
,testing_dayCounter,df_strategy,dayCounter_strategy)
if eval(cf.get("sec_e","is_training_rawData"))==False :
# 调用gap_handle函数来进行价差处理
df_strategy = self.gap_handle(self.gap_dataframe,training_dayCounter\
,testing_dayCounter,df_strategy,dayCounter_strategy)
# =========================================================
# 参数代表意义:
# training:训练周期(数据类型:int)
# testing:测试周期(数据类型:int)
# dataType:期货数据类型,例如'IF_d1'(数据类型:Str)
# path_file:涨跌信号存储路径及文件名(数据类型:Str)
# dataframe:当前可取的所有数据DataFrame(数据类型:<class 'pandas.core.frame.DataFrame'>)
# days:当前日期时间点(数据类型:<class 'pandas.tslib.Timestamp'>)
# dayCounter:计算当天是第几天,从0开始数起(数据类型:int)
# training_days:计算当前数据训练周期应该开始的时间点(数据类型:<class 'pandas.tslib.Timestamp'>)
# training_dayCounter:计算当前数据训练周期应该开始的点是第几天(数据类型:int)
# testing_days:计算当前数据测试周期应该开始的时间点(数据类型:<class 'pandas.tslib.Timestamp'>)
# testing_dayCounter:计算当前数据测试周期应该开始的点是第几天(数据类型:int)
# trading_date:所有交易日列表(数据类型:<class 'pandas.tseries.index.DatetimeIndex'>)
# =========================================================
train(training = self.training, testing = self.testing, dataType = self.dataType, path_file = path_file\
, dataframe = df_strategy, days = self.df.index[dayCounter_strategy], dayCounter = dayCounter_strategy\
, training_days = self.df.index[training_dayCounter], training_dayCounter = training_dayCounter\
, testing_days = self.df.index[testing_dayCounter], testing_dayCounter = testing_dayCounter\
, trading_date = df_strategy_date)
# 当前是最后一个循环周期时进行的策略,将所有数据传给策略
if dayCounter_strategy == len(self.df)-1:
# 当前时间能取到的所有数据,即当前日期之前的所有数据
df_strategy = self.df
# 处理边缘的training_Counter和testing_Counter计算问题,即是否Out of bound
training_dayCounter = self.testing*training_testing_round
# 如果只存在不完整的训练周期,而完全不存在测试周期,则跳过最后一轮
if dayCounter_strategy<(training_dayCounter+self.training) :
pass
# 如果存在完整的训练周期和不完整的测试周期,则处理最后一轮
if dayCounter_strategy>=(training_dayCounter+self.training) :
testing_dayCounter = training_dayCounter+self.training
# 根据配置文件中设置,来判断训练周期是否进行价差处理
if eval(cf.get("sec_e","is_training_rawData"))==True :
# 调用gap_handle_rawTrain函数来进行价差处理
df_strategy = self.gap_handle_rawTrain(self.gap_dataframe,training_dayCounter\
,testing_dayCounter,df_strategy,dayCounter_strategy)
if eval(cf.get("sec_e","is_training_rawData"))==False :
# 调用gap_handle函数来进行价差处理
df_strategy = self.gap_handle(self.gap_dataframe,training_dayCounter\
,testing_dayCounter,df_strategy,dayCounter_strategy)
# =========================================================
# 参数代表意义:
# training:训练周期(数据类型:int)
# testing:测试周期(数据类型:int)
# dataType:期货数据类型,例如'IF_d1'(数据类型:Str)
# path_file:涨跌信号存储路径及文件名(数据类型:Str)
# dataframe:当前可取的所有数据DataFrame(数据类型:<class 'pandas.core.frame.DataFrame'>)
# days:当前日期时间点(数据类型:<class 'pandas.tslib.Timestamp'>)
# dayCounter:计算当天是第几天,从0开始数起(数据类型:int)
# training_days:计算当前数据训练周期应该开始的时间点(数据类型:<class 'pandas.tslib.Timestamp'>)
# training_dayCounter:计算当前数据训练周期应该开始的点是第几天(数据类型:int)
# testing_days:计算当前数据测试周期应该开始的时间点(数据类型:<class 'pandas.tslib.Timestamp'>)
# testing_dayCounter:计算当前数据测试周期应该开始的点是第几天(数据类型:int)
# trading_date:所有交易日列表(数据类型:<class 'pandas.tseries.index.DatetimeIndex'>)
# =========================================================
train(training = self.training, testing = self.testing, dataType = self.dataType, path_file = path_file\
, dataframe = df_strategy, days = self.df.index[dayCounter_strategy], dayCounter = dayCounter_strategy\
, training_days = self.df.index[training_dayCounter], training_dayCounter = training_dayCounter\
, testing_days = self.df.index[testing_dayCounter], testing_dayCounter = testing_dayCounter\
, trading_date = df_strategy_date)
class Performance(object) :
def __init__(self,account):
self.account = account
# 将时间由String类型转化为Date类型
def str2date(self,timeStr):
timeDate = datetime.datetime.strptime(timeStr[0:10], '%Y-%m-%d').date()
return timeDate
# 将时间由String类型转化为Datetime类型
def str2datetime(self,timeStr):
timeDate = datetime.datetime.strptime(timeStr, '%Y-%m-%d %H:%M:%S')
return timeDate
# 将时间由Datetime类型转化成String类型,精度低的
def datetime2str(self,strTime):
strDate = strTime.strftime('%Y-%m-%d')
return strDate
# 将时间由Datetime类型转化成String类型,精度高的
def datetime2string(self,strTime):
strDate = strTime.strftime('%Y-%m-%d %H:%M:%S')
return strDate
# 添加属性
def addAttribute(self):
# 每天的收益率情况计算
temp = []
for i in range(len(self.account.df)):
temp.append((self.account.df['capital'][i]-self.account.capital_init)/self.account.capital_init)
self.account.df['dayProfitRate'] = pandas.Series(temp,index = self.account.df.index)
# 分钟数据日期去重处理,可用于计算年化收益的实际交易天数
def data_min_date_list(self,df_temp):
# 建立一个date的集合,用于去重
date_set = set()
for i in range(len(df_temp)):
strDate = self.datetime2str(df_temp.index[i])
date_set.add(strDate)
# 将集合转化为list形式,以便能通过下标访问
date_min_list = list(date_set)
date_min_list.sort()
return date_min_list
# 计算年化收益率
def calculate_ratio(self,start,end):
start = self.str2datetime(start)
end = self.str2datetime(end)
# index切片截取所需部分的df
account_temp = self.account.df[start:end]
account_temp_day_list = self.data_min_date_list(account_temp)
# 年化收益率
# 公式 : 年化收益率=[(投资内收益 / 本金)/ 投资天数] * 365 ×100%
# 暂时还未跳过策略开始时的第一次training周期
annualized_returns_ratio = ((account_temp['capital'][len(account_temp)-1] - account_temp['capital'][0])/account_temp['capital'][0])/len(account_temp_day_list) *243
print "年化收益率 : ",annualized_returns_ratio
performance_list.append("年化收益率 : %s"%annualized_returns_ratio)
return annualized_returns_ratio
# 计算最大回撤率、最大回撤周期、最大回撤恢复周期
def calculate_draw_down_and_recovery(self,start,end):
start = self.str2datetime(start)
end = self.str2datetime(end)
account_temp = self.account.df[start:end] # index切片截取所需部分的df
print "时段 : %s ~ %s"%(account_temp.index[0],account_temp.index[len(account_temp)-1])
performance_list.append("时段 : %s ~ %s"%(account_temp.index[0],account_temp.index[len(account_temp)-1]))
draw_down = [] # 每个点的最大回撤率列表
capital_list = [] # 导出每个点的capital值到一个列表中
for n in range(len(account_temp)):
# 计算每个点的最大回撤率
draw_down.append(1 - (account_temp['capital'][n])/max(account_temp[0:n+1]['capital']))
# 导出每个点的capital值到列表中
capital_list.append(account_temp['capital'][n])
# 找到每个点最大回撤率列表中的全局最大回撤率
max_draw_down = max(draw_down)
# 得到最大回撤率值的index2,即回撤结束时间为index2
index2 = draw_down.index(max_draw_down)
# 从0~index1个数据集中,得到当前最大数值的index1,即回撤开始时间为index1
index1 = capital_list.index(max(capital_list[0:index2]))
print "最大回撤率 : %s"%(max_draw_down)
print "最大回撤周期 : %s ~ %s"%(account_temp.index[index1],account_temp.index[index2])
performance_list.append("最大回撤率 : %s"%(max_draw_down))
performance_list.append("最大回撤周期 : %s ~ %s"%(account_temp.index[index1],account_temp.index[index2]))
# 计算最大回撤恢复周期
for i in range(index1,len(capital_list)):
if capital_list[i] > capital_list[index1] :
# 恢复结束时间index3
index3 = i
print "最大回撤恢复周期 : %s ~ %s"%(account_temp.index[index1],account_temp.index[index3])
performance_list.append("最大回撤恢复周期 : %s ~ %s"%(account_temp.index[index1],account_temp.index[index3]))
break
if i == (len(capital_list)-1) :
print "最大回撤恢复周期 : -1"
performance_list.append("最大回撤恢复周期 : -1")
return max_draw_down
# 计算F_ value值(公式:F_value = 年化收益率/最大回撤率)
def calculate_F_value(self,annualized_returns_ratio,max_draw_down):
F_value = annualized_returns_ratio/max_draw_down
print "F_value : ",F_value
performance_list.append("F_value : %s"%F_value)
# 计算命中率(胜率)
def getHitRate(self,start,end):
start = self.str2datetime(start)
end = self.str2datetime(end)
account_temp = self.account.df[start:end] # index切片截取所需部分的df
gain_hit = 0.0 # 命中的个数
loss_hit = 0.0 # 未命中的个数
hitRate = 0.0 # 命中率
# 统计命中和未命中的个数
for i in range(len(account_temp)):
if account_temp['hit'][i] > 0 :
gain_hit += 1
if account_temp['hit'][i] < 0 :
loss_hit += 1
# 计算命中率
try:
hitRate = gain_hit/(gain_hit+loss_hit)
except ZeroDivisionError, e:
hitRate = 0.0
print "命中率 : ",hitRate
performance_list.append("命中率 : %s"%hitRate)
# performance_hit.append("命中率 : %s"%hitRate)
# 计算平均收益除于平均亏损,(平均方法:平均收益 = 盈利点数/盈利手数,平均亏损 = 亏损点数/亏损手数)
def gain_divide_loss(self,start,end):
start = self.str2datetime(start)
end = self.str2datetime(end)
account_temp = self.account.df[start:end] # index切片截取所需部分的df
gain_point = 0.0 # 盈利点数
gain_num = 0 #盈利手数
loss_point = 0.0 #亏损点数
loss_num = 0 #亏损手数
gainDivideLoss = 0.0 # 平均收益除于平均亏损
# 统计盈利点数和盈利手数,亏损点数和亏损手数
for i in range(len(account_temp)):
# 点数大于0,统计盈利的点数和手数
if account_temp['point_num'][i] > 0 :
gain_point += account_temp['point_num'][i]
gain_num += account_temp['order_num'][i]
# 点数小于0,统计亏损的点数和手数
if account_temp['point_num'][i] < 0 :
loss_point += ( - account_temp['point_num'][i])
loss_num += account_temp['order_num'][i]
# 计算平均收益除于平均亏损
try:
# 计算平均收益除于平均亏损
gainDivideLoss = (gain_point/gain_num)/(loss_point/loss_num)
except ZeroDivisionError, e:
# 如果分母为0,则平均收益除于平均亏损等于0
gainDivideLoss = 0.0
print "平均收益除于平均亏损 : ",gainDivideLoss
performance_list.append("平均收益除于平均亏损 : %s"%gainDivideLoss)
# 计算总体的指标
def calculate_total(self):
# end往后推一天,使时间段中包括最后一天
end = self.str2datetime(self.account.end)
end = end + datetime.timedelta(days=1)
end = self.datetime2string(end)
# 总体最大回撤率、最大回撤周期、最大回撤恢复周期
max_draw_down = self.calculate_draw_down_and_recovery(self.account.start,end)
# 总体年化收益率
annualized_returns_ratio = self.calculate_ratio(self.account.start,end)
# 总体F_value值
self.calculate_F_value(annualized_returns_ratio,max_draw_down)
# 总体命中率
self.getHitRate(self.account.start,end)
# 总体平均收益除于平均亏损
self.gain_divide_loss(self.account.start,end)
# 计算每年的指标
def calculate_year(self):
# 记录每年的开始日期和结束日期,奇数为开始时间,偶数为结束时间,type = datetime.date
date_list = [self.account.df.index[0]]
# 当前年份
current_year = self.account.df.index[0].year
# 提取每年的开头和结尾日期
for i in range(len(self.account.df)):
# 判断是否跨年
if self.account.df.index[i].year != current_year :
# 上一个时间段的结束时间
date_list.append(self.account.df.index[i-1])
# 下一个时间段的开始时间
date_list.append(self.account.df.index[i])
# 更新当前年份
current_year = self.account.df.index[i].year
# 判断是否为最后一个时间点
if i == (len(self.account.df)-1) :
date_list.append(self.account.df.index[i])
# 逐年处理数据,计算指标
for y in range(len(date_list)/2):
start = str(date_list[y*2])
end = str(date_list[y*2+1])
print "-------------%s年---------------"%(date_list[y*2].year)
performance_list.append("-------------%s年---------------"%(date_list[y*2].year))
# performance_hit.append("-------------%s年---------------"%(date_list[y*2].year))
# 计算最大回撤率,最大回撤周期,最大回撤恢复周期
try :
max_draw_down = self.calculate_draw_down_and_recovery(start,end)
except :
max_draw_down = -1
# 计算年化收益率
annualized_returns_ratio = self.calculate_ratio(start,end)
# 计算F_value值
self.calculate_F_value(annualized_returns_ratio,max_draw_down)
# 计算命中率
self.getHitRate(start,end)
# 计算平均收益除于平均亏损
self.gain_divide_loss(start,end)
# 画图
def performance(self,dataType):
picture2 = pandas.DataFrame(self.account.df['dayProfitRate'] ,index = self.account.df.index)
# matplotlib.pyplot.figure()
picture2.plot()
# 显现图片后,是否保存图片
want_save_picture = eval(cf.get("sec_b","want_save_picture"))
# 显现图片后,自动保存图片到指定目录下
if want_save_picture == True:
# 显现图片
matplotlib.pyplot.show()
# 自动保存图片
# 数字代表意义分别是:训练周期_测试周期_止损点_止盈阈值_止盈点
savefig('%s%s_%s_%s_%s_%s_%s.png'%(path_saving_picture,dataType,self.account.training,self.account.testing,\
self.account.stop_loss_point,self.account.monitor_threshold,self.account.stop_earning_point))
# 仅显现图片,不保存
if want_save_picture == False:
# 显现图片
matplotlib.pyplot.show()
# 天数据级别的最好调用这个
# main()方法,每日进行一次交易,跑期货策略时或择时测试时使用
def future_timing_one_main():
global performance_list
# -----------------------------------------------------
# 训练测试比的步长
step = 10
# -----------------------------------------------------
# 遍历不同类型期货
for dataType_yuan in dataType_list:
# 处理,添加后缀
dataType = "%s_%s"%(dataType_yuan,data_granularity)
# 当前期货类型
print "当前期货类型 : ",dataType
# 遍历止损点,从5~50个最小变动单位,步数为5
# for stop_loss_point_multiple in range(5,51,5):
for stop_loss_point_multiple in [50]:
# 遍历监控阈值,从50~150个最小变动单位,步数为5
# for monitor_threshold in range(50,151,5):
for monitor_threshold in [150]:
# 遍历止盈点,从5~50个最小变动单位,步数为5
# for stop_earning_point in range(5,51,5):
for stop_earning_point in [50]:
# # 数据库中含有当前期货类型名的表
# try:
account = Account(dataType_yuan,stop_loss_point_multiple,monitor_threshold,stop_earning_point) # 实例化一个account账号
print "训练测试比 = %s : %s"%(account.training,account.testing) # 当前训练测试比
# train(account.training,account.testing,dataType,path_file) # 调用策略函数,生成信号的txt文件
account.getData() # 取数据
account.handle_strategy() # 统一数据,调用策略函数,生成信号的txt文件
account.appendAttribute() # 增加属性
# 遍历每一天
while account.dayCounter < len(account.df) :
# 当前时间
account.current_time = account.df.index[account.dayCounter]
print "当前时间:",account.current_time
# 输出当前资产
print "当前资产:",account.capital
# 提取出当前涨跌信号
account.signal = account.df['signal'][account.dayCounter]
# 根据输入文件中买卖价格的自定义情况来确定account中的买卖价格
if (self_define_order_price == False) and (self_define_sell_price == False) :
account.orderPrice = account.df['open'][account.dayCounter]
account.sellPrice = account.df['close'][account.dayCounter]
if (self_define_order_price == True) and (self_define_sell_price == False) :
account.orderPrice = account.df['order'][account.dayCounter]
account.sellPrice = account.df['close'][account.dayCounter]
if (self_define_order_price == False) and (self_define_sell_price == True) :
account.orderPrice = account.df['open'][account.dayCounter]
account.sellPrice = account.df['sell'][account.dayCounter]
if (self_define_order_price == True) and (self_define_sell_price == True) :
account.orderPrice = account.df['order'][account.dayCounter]
# 根据signal判断涨跌,从而计算收益
if account.signal > 0 :
# 买进期货
account.order()
# 计算盈利(亏损)的点数,正为盈利,负为亏损
point_num_temp = account.sellPrice - account.orderPrice
account.df['point_num'][account.dayCounter] = point_num_temp
# 计算盈利(亏损)的总金额,正为盈利,负为亏损
account.earn = (point_num_temp)*account.order_num*account.contract_multiple
# 买进的手数
account.df['order_num'][account.dayCounter] = account.order_num
# 命中率计算
if account.earn > 0 :
account.df['hit'][account.dayCounter] = 1
# print "--------------------------hit up------------------------"
if account.earn < 0 :
account.df['hit'][account.dayCounter] = -1
# 想要添加止损时
if want_stop_loss == True:
# 调用止损
# 如果不是最后一天的话,这样止损
if account.dayCounter != (len(account.df)-1) :
# 止损(止盈)
account.stop_loss(account.df.index[account.dayCounter] , account.df.index[account.dayCounter+1] , account.signal , account.order_num)
# 如果是最后一天的话,这样止损
if account.dayCounter == (len(account.df)-1) :
# 止损(止盈)
account.stop_loss(account.df.index[account.dayCounter] , account.df.index[account.dayCounter]+datetime.timedelta(days=1) , account.signal , account.order_num)
# 不想添加止损时
if want_stop_loss == False:
pass
# 卖出期货
account.sell()
if account.signal < 0 :
# 买进期货
account.order()
# 计算盈利(亏损)的点数,正为盈利,负为亏损
point_num_temp = account.orderPrice - account.sellPrice
account.df['point_num'][account.dayCounter] = point_num_temp
# 计算盈利(亏损)的总金额,正为盈利,负为亏损
account.earn = (point_num_temp)*account.order_num*account.contract_multiple
# 买进的手数
account.df['order_num'][account.dayCounter] = account.order_num
# 命中率计算
if account.earn > 0 :
account.df['hit'][account.dayCounter] = 1
# print "--------------------------hit down------------------------"
if account.earn < 0 :
account.df['hit'][account.dayCounter] = -1
# 想要添加止损时
if want_stop_loss == True:
# 调用止损
# 如果不是最后一天的话,这样止损
if account.dayCounter != (len(account.df)-1) :
# 止损(止盈)
account.stop_loss(account.df.index[account.dayCounter] , account.df.index[account.dayCounter+1] , account.signal , account.order_num)
# 如果是最后一天的话,这样止损
if account.dayCounter == (len(account.df)-1) :
# 止损(止盈)
account.stop_loss(account.df.index[account.dayCounter] , account.df.index[account.dayCounter]+datetime.timedelta(days=1) , account.signal , account.order_num)
# 不想添加止损时
if want_stop_loss == False:
pass
# 卖出期货
account.sell()
# print "--------------point_num_temp : %s---------------"%(account.df['point_num'][account.dayCounter])
# print "--------------account.order_num : %s------------"%(account.order_num)
# print "--------------account.contract_multiple : %s---"%(account.contract_multiple)
if account.signal == 0 :
# 记录每天动态资产变化情况,在sell()方法中计算的值
account.df['capital'][account.dayCounter] = account.capital
# 天数加一
account.dayCounter += 1
# 计算各种指数
perf = Performance(account)
perf.addAttribute()
# 计算总体的指标
perf.calculate_total()
# 计算每年的指标
perf.calculate_year()
# 整个表
print perf.account.df
# 将表里的各种细节记录下来
perf.account.df.to_csv(path_or_buf = './df.csv' , sep = ',')
# 写入文件
with open(path_performance, 'a+') as f :
# 数字代表意义分别是:训练周期 : 测试周期_止损点_止盈阈值_止盈点
f.write('-------------%s_%s : %s_%s_%s_%s---------------\n'%(dataType,account.training,account.testing,\
account.stop_loss_point,account.monitor_threshold,account.stop_earning_point))
for i in performance_list :
f.write('%s\n'%i)
# for i in performance_hit:
# f.write('%s\n'%i)
performance_list = [] # 写入后清空,以便下一次记录数据
# performance_hit = []
f.write('\n\n')
# # 记录每天的动态收益
# for i in range(len(account.df)):
# f.write('%s,%s\n'%(account.df.index[i],account.df['capital'][i]))
# f.write('\n\n')
# 画图
perf.performance(dataType)
# # 数据库中不含当前期货类型名的表
# except pandas.io.sql.DatabaseError, e:
# continue
# 天以下级别的数据最好调用这个
# main()方法,每日进行多次交易,跑期货策略使用
def future_multiple_main():
global performance_list
# 遍历不同类型的期货
for dataType_yuan in dataType_list:
# 处理,添加后缀
dataType = "%s_%s"%(dataType_yuan,data_granularity)
# 当前期货类型
print "当前期货类型 : ",dataType
# 遍历止损点,从5~50个最小变动单位,步数为5
# for stop_loss_point_multiple in range(5,51,5):
for stop_loss_point_multiple in [50]:
# 遍历监控阈值,从50~150个最小变动单位,步数为5
# for monitor_threshold in range(50,151,5):
for monitor_threshold in [150]:
# 遍历止盈点,从5~50个最小变动单位,步数为5
# for stop_earning_point in range(5,51,5):
for stop_earning_point in [50]:
# 实例化一个account账号
account = Account(dataType_yuan,stop_loss_point_multiple,monitor_threshold,stop_earning_point)
# 当前训练测试比
print "训练测试比 = %s : %s"%(account.training,account.testing)
# # 调用策略函数,生成信号的txt文件
# train(account.training,account.testing,dataType,path_file)
# 取分钟数据
account.getData()
account.handle_strategy()
# 增加属性
account.appendAttribute()
# 遍历每一分钟
for account.minCounter in range(len(account.df)):
# 输出当前时间
account.current_time = account.df.index[account.minCounter]
print "当前时间:",account.current_time
# 输出当前资产
print "当前资产:",account.capital
# 上一个涨跌信号
if account.minCounter != 0 :
account.presignal = account.df['signal'][account.minCounter-1]
# 当前涨跌信号
account.signal = account.df['signal'][account.minCounter]
# 当前为第一分钟时
if account.minCounter==0:
if account.signal > 0 or account.signal < 0 :
# 定义买入价格
account.orderPrice = account.df['open'][account.minCounter]
# 买进期货
account.order()
# 更新交易时间点
account.trading_point = account.minCounter
if account.signal == 0 :
pass
# 想要添加止损时
if want_stop_loss == True:
# 下单时,进行止损判断
# 之前没有止损过的情况
if account.is_stop_loss == False:
# 当上一次止损信号和当前止损信号相同时,用上一次涨跌信号止损
if account.signal == account.presignal:
# 止损止盈
account.stop_loss(account.df.index[account.trading_point] , account.current_time , account.presignal , account.order_num)
# 当上一次止损信号和当前止损信号不同时,不止损
if account.signal != account.presignal:
# 不止损
pass
# 如果经过止损函数的计算,止损信号变为True
if account.is_stop_loss == True :
# 卖出期货
account.sell_min()
# 买进的手数
account.df['order_num'][account.minCounter] = account.order_num
# 止损(止盈)损失(赚取)的点数
account.df['point_num'][account.minCounter] = account.point_num
# 清零
account.order_num = 0
account.point_num = 0.0
# 如果经过止损函数的计算,止损信号仍然为False
if account.is_stop_loss == False:
pass
# 之前止损过的情况
if account.is_stop_loss == True :
pass
# 不想添加止损时
if want_stop_loss == False:
pass
# 当前为最后一分钟时
if account.minCounter==(len(account.df)-1) :
# 定义卖出价格,以最后一分钟的收盘价平仓
account.sellPrice = account.df['close'][account.minCounter]
# 计算盈利(亏损)的点数,正为盈利,负为亏损
point_num_temp = account.sellPrice - account.orderPrice
account.df['point_num'][account.minCounter] = point_num_temp
# 计算盈利(亏损)的总金额,正为盈利,负为亏损
account.earn = (point_num_temp)*account.order_num*account.contract_multiple
# 买进的手数
account.df['order_num'][account.minCounter] = account.order_num
# 如果当前信号为0
if account.signal == 0 or account.is_stop_loss == True:
account.df['point_num'][account.minCounter] = 0.0
account.df['order_num'][account.minCounter] = 0
# 命中率计算
if account.signal > 0 :
if (account.df['close'][account.minCounter] - account.df['open'][account.trading_point]) > 0 :
account.df['hit'][account.minCounter] = 1
# print "--------------------------hit up------------------------"
if (account.df['close'][account.minCounter] - account.df['open'][account.trading_point]) < 0 :
account.df['hit'][account.minCounter] = -1
if account.signal < 0:
if (account.df['open'][account.trading_point] - account.df['close'][account.minCounter]) > 0 :
account.df['hit'][account.minCounter] = 1
# print "--------------------------hit down------------------------"
if (account.df['open'][account.trading_point] - account.df['close'][account.minCounter]) < 0 :
account.df['hit'][account.minCounter] = -1
# 如果之前没有过止损时
if account.is_stop_loss == False:
# 卖出期货
account.sell_min()
# 当前不为第一分钟和最后一分钟时
if account.minCounter != 0 and account.minCounter != (len(account.df)-1) :
# 如果当前涨跌信号和上一次涨跌信号不同
if account.signal != account.presignal:
# 如果上一分钟信号大于0
if account.presignal > 0 :
# 定义卖出价格,信号变化前最后一分钟的收盘价平仓
account.sellPrice = account.df['close'][account.minCounter-1]
# 计算盈利(亏损)的点数,正为盈利,负为亏损
point_num_temp = account.sellPrice - account.orderPrice
# 如果之前没有过止损时
if account.is_stop_loss == False:
account.df['point_num'][account.minCounter-1] = point_num_temp
# 如果之前已经有过止损时
if account.is_stop_loss == True:
account.df['point_num'][account.minCounter-1] = 0.0
# 计算盈利(亏损)的总金额,正为盈利,负为亏损
account.earn = (point_num_temp)*account.order_num*account.contract_multiple
# 买进的手数
account.df['order_num'][account.minCounter-1] = account.order_num
# 命中率计算
if point_num_temp > 0 :
account.df['hit'][account.minCounter-1] = 1
# print "--------------------------hit up------------------------"
if point_num_temp <= 0 :
account.df['hit'][account.minCounter-1] = -1
# 如果之前没有过止损时
if account.is_stop_loss == False:
# 卖出期货
account.sell_min()
# 如果这一分钟信号小于0
if account.signal < 0 :
# 定义买入价格
account.orderPrice = account.df['open'][account.minCounter]
# 买进期货
account.order()
# 如果这一分钟信号等于0
if account.signal == 0 :
# 持有的手数清零
# account.df['order_num'][account.minCounter] = 0
account.order_num = 0
# 赚取(亏损)点数清零
account.point_num = 0.0
# account.df['point_num'][account.minCounter] = 0
# 如果上一分钟信号小于0
if account.presignal < 0 :
# 定义卖出价格,信号变化前最后一分钟的收盘价平仓
account.sellPrice = account.df['close'][account.minCounter-1]
# 计算盈利(亏损)的点数,正为盈利,负为亏损
point_num_temp = account.orderPrice - account.sellPrice
# 如果之前没有过止损时
if account.is_stop_loss == False:
account.df['point_num'][account.minCounter-1] = point_num_temp
# 如果之前已经有过止损时
if account.is_stop_loss == True:
account.df['point_num'][account.minCounter-1] = 0.0
# 计算盈利(亏损)的总金额,正为盈利,负为亏损
account.earn = (point_num_temp)*account.order_num*account.contract_multiple
# 买进的手数
account.df['order_num'][account.minCounter-1] = account.order_num
# 命中率计算
if point_num_temp > 0 :
account.df['hit'][account.minCounter-1] = 1
# print "--------------------------hit down------------------------"
if point_num_temp <= 0 :
account.df['hit'][account.minCounter-1] = -1
# 如果之前没有过止损时
if account.is_stop_loss == False:
# 卖出期货
account.sell_min()
# 如果这一分钟信号大于0
if account.signal > 0 :
# 定义买入价格
account.orderPrice = account.df['open'][account.minCounter]
# 买进期货
account.order()
# 如果这一分钟信号等于0
if account.signal == 0 :
# 持有的手数清零
account.order_num = 0
# account.df['order_num'][account.minCounter] = 0
# 赚取(亏损)点数清零
account.point_num = 0.0
# account.df['point_num'][account.minCounter] = 0
# 如果上一分钟信号等于0
if account.presignal == 0 :
# 定义买入价格
account.orderPrice = account.df['open'][account.minCounter]
# 买进期货
account.order()
# 止损信号变成False,准备进行新一轮止损
account.is_stop_loss = False
# 当前信号为0时,不进行止损判断
if account.signal == 0:
account.is_stop_loss = True
# 更新交易时间点
account.trading_point = account.minCounter
# 记录动态资产变化情况
account.df['capital'][account.minCounter] = account.capital
# 计算各种指数
perf = Performance(account)
perf.addAttribute()
# 计算总体的指标
perf.calculate_total()
# 计算每年的指标
perf.calculate_year()
# 输出整个表
print perf.account.df
# 将表里的各种细节记录下来
perf.account.df.to_csv(path_or_buf = './df.csv' , sep = ',')
# 写入文件
with open(path_performance, 'a+') as f :
# 数字代表意义分别是:训练周期 : 测试周期_止损点_止盈阈值_止盈点
f.write('-------------%s_%s : %s_%s_%s_%s---------------\n'%(dataType,account.training,account.testing,\
account.stop_loss_point,account.monitor_threshold,account.stop_earning_point))
for i in performance_list :
f.write('%s\n'%i)
# 写入后清空,以便下一次记录数据
performance_list = []
# 格式控制
f.write('\n\n')
# 画图
perf.performance(dataType)
# main()方法,分布式
def parallel_main():
# 期货类型
dataType = "IF_d1"
# 创建Client
c = Client()
# Remote import(远程导入模块)
with c[:].sync_imports():
# from gaojieju import train # 测试用模块(高阶矩)
from FutureHmm import train # 测试用模块(HMM)
# from anfis import train # 测试用模块(神经网络)
# # 为每个engine导入不同的内容
# for id_engine in c.ids:
# dview = c[id_engine]
# dview.block = False
# ar = dview.apply(train,train_num)
# 训练次数范围、步长
train_list_temp = range(50,56,5)
# 测试次数范围、步长
test_list_temp = range(50,56,5)
train_list = []
test_list = []
# 处理输入的train列表
for train_element in train_list_temp:
for i in range(len(test_list_temp)):
train_list.append(train_element)
# 处理输入的test列表
for i in range(len(train_list_temp)):
test_list.extend(test_list_temp)
# 同步进行
r = c[:].map_sync(train,train_list,test_list)
# =========================================================
# 将下单时间点输出到一个文件中去:
# (1)文件名格式:
# 策略名_期货类型_时间周期_训练周期_测试周期
# 例子:
# HMM_IF_d1_110_50
# (2)文件内容格式:
# 当前时间点,涨跌信号,当前训练测试周期的起始点
# 例子:
# 2010-04-29 10:00:00,1,2010-04-16 09:00:00
# 要求:补全所有时间点
# =========================================================
def file_format_output(training,testing):
# 读取涨跌信号文件
signal_file = np.loadtxt(path_file,delimiter=",", usecols=[0,1],dtype=str)
signal_file_temp = signal_file.tolist()
current_round_start_point = 0
for i in range(len(signal_file_temp)):
# 当前为第一轮的时候,补全training内的周期初始时间
if i==0 :
for j in range(training):
signal_file_temp[j].append(signal_file_temp[0][0])
# 当前不为第一轮时,通用的数据处理方法
# 更新周期起始点
if (i-training)%testing==0 and (i-training)>=0:
current_round_start_point = i-training
# 根据最新的周期起始点进行list写入操作
if (i-training)>=0:
signal_file_temp[i].append(signal_file_temp[current_round_start_point][0])
# 将数据写入文件中
path_file_temp = "./%s_%s_%s_%s_%s.txt"%(cf.get("sec_d","strategy_name"),\
eval(cf.get("sec_b","dataType_list"))[0],cf.get("sec_b","data_granularity"),\
training,testing)
with open(path_file_temp,'w+') as f:
for i in range(len(signal_file_temp)):
# 删除冗余数据,只保留训练测试周期起始时间点和信号量变化时间点
# 当前数据不是最后一个数据
if i!=(len(signal_file_temp)-1) :
if signal_file_temp[i][1]!=signal_file_temp[i+1][1]\
or signal_file_temp[i][2]!=signal_file_temp[i+1][2] :
f.write('%s,%s,%s\n'%(signal_file_temp[i][0],signal_file_temp[i][1],signal_file_temp[i][2]))
# 当前数据是最后一个数据
if i==(len(signal_file_temp)-1) :
f.write('%s,%s,%s\n'%(signal_file_temp[i][0],signal_file_temp[i][1],signal_file_temp[i][2]))
if __name__ == '__main__' :
# 计算程序运行时间
# 程序开始运行时间
time_start = time.time()
# --------------------------------------------------------------------
# 平台调用信号,用来调用不同种类平台
call_platform_signal = cf.getint("sec_c","call_platform_signal")
if call_platform_signal == 1:
# 天数据,开盘买,收盘卖
future_timing_one_main()
if call_platform_signal == 2:
# 分布式
parallel_main()
if call_platform_signal == 3:
# 兼容各种数据级别,日内、跨日、不定时交易
future_multiple_main()
# --------------------------------------------------------------------
if eval(cf.get("sec_d","order_point_file"))==True:
file_format_output(eval(cf.get("sec_a","training")),eval(cf.get("sec_a","testing")))
# --------------------------------------------------------------------
# 程序结束运行时间
time_end = time.time()
print "运行时间:%f s"%(time_end - time_start)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。