用python写了一个简单的多空交易的测试代码

其中的空头部分用分级基金A,多头部分用跟踪同样指数的etf基金

测试的不是很理想。

由于刚开始接触python,所以在编写代码时已实现功能为主,还有很多可以改进的地方。十分欢迎有相同爱好的朋友一起交流。代码如下

from __future__ import division
 import tushare as ts
 import pandas as pd
 import numpy as np
 import csv

 init_money=100000      

 def file2data(filename):        #将文件中的历史数据以一个列表的形式返回
         str_filename="../data/"+filename
         f=open(str_filename)    #打开文件
         lines=f.readlines()     #读取文件中的所有行
         lst=[]                  #一个空的列表,用于存储文件数据
         i=0
         for line in lines:
                 if i==0:        #跳过第一行
                         i+=1
                         continue
                 else:
                         lst.append(line)

         f.close()
         return lst      #返回数据

 def equalData(filename):        #将两个投资标的的历史数据进行等长化处理,filename用于一个列表数据更好
         lst=[]                  #空列表用于存储各标的的历史数据
         lens=[]                 #空列表用于存储各标的历史数据的长度
         for i in range(len(filename)):
                 lst.append(file2data(filename[i]))
                 lens.append(len(lst[i]))

         #此时lst为一个二维列表,两个元素,每一个元素为对应投资标的的历史数据
         if lens[0]==lens[1]:    #如果长度相等,则返回两个列表,分别对应各自的历史数据
                 return lst[0],lst[1]
         elif lens[0]<lens[1]:   #表示投资标的0晚于投资标的1上市,所以以标的0为准进行等长化处理
                 data=lst[1][:lens[0]]
                 return lst[0],data
         else:
                 data=lst[0][:lens[1]]
                 return data,lst[1]

 def reverseData(hist_data):     #按照时间顺序重新排列数据(由远及近)
         data=hist_data[::-1]
         return data

 def initOrder(data1,data2):     #建仓函数,用于第一次交易,返回两个投资标的的持仓数
         money_for_target1=money_for_target2=init_money*0.5      #可以用在单一标的上的资金

         data1_list=str2list(data1[0])                                   #将字符串类型的历史数据转换为列表类型
         data2_list=str2list(data2[0])

         price_target1=float(data1_list[3])                              #将字符串类型的收盘价转换为整数类型
         price_target2=float(data2_list[3])

         share_for_target1=round(money_for_target1/price_target1,0)
         share_for_target1=share_for_target1-share_for_target1%100       #确保持仓数为100的整数倍
         share_for_target2=round(money_for_target2/price_target2,0)
         share_for_target2=share_for_target2-share_for_target2%100
         remain_money=init_money-price_target1*share_for_target1-price_target2*share_for_target2
         return data1_list[0],share_for_target1,float(data1_list[3]),share_for_target2,float(data2_list[3]),remain_money

 def str2list(data):     #因为历史数据中的每一行都是以字符串格式存储,所以需要将每一行的历史数据换成列表形式
         list_data=data.split(',')
         return list_data

 def rebalance(sum_money,price_for_short,price_for_bull):
 #仓位再平衡函数,将仓位重新回到50-50
 #输入参数:当前总价值、空头部分单价、多头部分单价
 #输出参数:再平衡后的空头部分持股,多头部分持股数,现金余额
         money_for_short=money_for_bull=sum_money*0.5      #可以用在单一标的上的资金

         share_for_short=round(money_for_short/price_for_short,0)
         share_for_short=share_for_short-share_for_short%100

         share_for_bull=round(money_for_bull/price_for_bull,0)
         share_for_bull=share_for_bull-share_for_bull%100

         remain_money=sum_money-price_for_short*share_for_short-price_for_short*share_for_short
         return share_for_short,share_for_bull,remain_moneydef is_year_first_tradeday(data):       #判断是否为一年的第一个交易日,为简化模型,分级A的折算在第一个交易日进行
 #输入参数为转换后的历史数据(即以时间为标准由远及近排列)
 #判断依据为前后两条数据的年份不同,则后一条数据即为当年的第一个交易日
 #返回参数为一个列表,用于存储所有历史数据中的第一个年度交易日
         year_first_record=data[0][0:4]  #第一条历史记录的年份
         year_previous_record=year_first_record  #前一条历史记录的年份

         year_list=[]
         for i in range(len(data)-1):
                 year_current_record=data[i+1][0:4]
                 if year_current_record==year_previous_record:
                         year_previous_record=year_current_record
                         #continue
                 else:
                         year_list.append(data[i+1][0:10])
                         year_previous_record=year_current_record

         return year_list

 def experiment_test(file_list):
 #该函数用于测试策略效果
 #读取数据文件
 #进行第一次初始化交易
 #每个交易日用收盘价
 #如果符合条件则在后一个交易日用收盘价进行再平衡
 #判断这个交易日是否是当年的第一个交易日,如果是第一个交易日则进行再平衡

 #输入参数为数据文件列表

         data1,data2=equalData(file_list)        #data_short表示空头数据, data_bull表示多头数据
         data_short=reverseData(data1)   #按照时间反序排列
         data_bull=reverseData(data2)
         date="" #交易日期
         share_for_short=0       #空头份额
         share_for_bull=0        #多头份额
         remain_money=0          #剩余金额
         sum_money=0             #总市值
         year_list=is_year_first_tradeday(data_short)    #用于找出回测期间内每年的第一个交易日
         #开始进行第一次交易,即初始化建仓交易
         date,share_for_short,init_short_price,share_for_bull,init_bull_price,remain_money=initOrder(data_short,data_bull)
         sum_money=share_for_short*init_short_price+share_for_bull*init_bull_price+remain_money
         print "the trade_date is %s,the hold share for short is %d,the hold share for bull is %d,the remain money is %f, the total value is %d" % (date,share_for_short,share_for_bull,remain_money,sum_money)


         #跳过第一条历史数据
         data_short.pop(0)
         data_bull.pop(0)

         for i in range(len(data_short)):
                 date=data_short[i][0:10]        #获取交易日期,此时data_short类表中的每一条历史数据还是以整个字符串为的形式
                 #将空头、多头的历史数据均转换成每一个元素都是列表的形式
                 pre_list_data_short=str2list(data_short[i])
                 pre_list_data_bull=str2list(data_bull[i])
                 #获取当天两个标的的收盘价               
                 price_for_short=float(pre_list_data_short[4])
                 price_for_bull=float(pre_list_data_bull[4])

                 sum_money=share_for_short*price_for_short+share_for_bull*price_for_bull+remain_money    #当日持仓总市值
                 short_value=share_for_short*price_for_short                                             #当日空头部分总市值
                 bull_value=share_for_bull*price_for_bull                                                #当日多头部分总市值

                 short_part=short_value/sum_money                                                        #分别计算多空占比
                 bull_part=bull_value/sum_money

                 if abs(short_part-bull_part)>0.4:       #即有一部分的仓位占比超过了70%,需要开始进行再平衡操作
                         share_for_short,share_for_bull,remain_monry=rebalance(sum_money,price_for_short,price_for_bull)
                         print "%s rebalance" % date
                 elif (date in year_list):       #如果是每年的第一个交易日,则进行定折
                         print "fist"
                         short_real_value=share_for_short*1.004  #按照4%的收益率进行折算
                         bull_real_value=share_for_bull*price_for_bull   #计算多头部分的市值
                         sum_money=real_sum_money=short_real_value+bull_real_value+remain_money  #计算折算后的总市值
                         share_for_short,share_for_bull,remain_monry=rebalance(real_sum_money,price_for_short,price_for_bull)

                 print "the trade_date is %s,the hold share for short is %d,the part is %f,the hold share for bull is %d,part is %f,the remain money is %f, the total value is %d" % (date,share_for_short,short_part,share_for_bull,bull_part,remain_money,sum_money)