您的位置:首页 > 其它

Julia: 基于CTA策略的回测可视化分析的尝试

2016-10-16 20:49 337 查看
相关库: Winston,Tk.

特点: 纯Julia打造,稀有,呵呵。

回测可视化的基本功能:

可以方便地看到当天日内交易每笔的买卖时点,当天的每笔盈亏情况。不用到行情中去查找和对照,那样太辛苦了。有了这个分析工具,可以大大提高了回测交易流水的分析效率。

可以前复盘,也可以向后复盘。可以自定义日期和标的。

这个分析工具主要是基于日内交易的,如果是基于跨日交易,其框架差不多,只需要做一部分小的修改就可以。

说明:

当Julia处在0.2时侯,这个东东已经投入使用。但有一阵子在Julia到0.4阶段,Wiston库也不跟着升级,导致用不上。这次看到Winston跟着Julia升到0.5了,甚喜。留做记念吧。

Winston画图功能有限,其实用PyPlot等其它的库替代 Winston也是可以的,我也试过。

代码如下:

using Tk
using Winston;
using StrategyData;

w     = Tk.Toplevel("策略复盘助手_日内策略",400,300)
f     = Tk.Frame(w);
Tk.pack(f, expand=true, fill="both")
ei    =  Tk.Entry(f) #输入标的
e     =  Tk.Entry(f) # 输入起始时间
rb    =  Tk.Radio(f, [ "向后复盘","向前复盘"])# 向前 或向后复盘
b     =  Tk.Button(f, "策略复盘请按=>Ok")
txt   =  Tk.Text(f, width=50,height=40)# 如果当日交易多,可以设置“height=40”,width=10,height=10
sc    =  Tk.Scrollbar(f,txt,"vertical")
map(u -> pack(u,side="left", anchor="w"), (ei,e, rb,b,txt,sc))     ## pack in left to right ,"left" : "top"、"n","w"
# 布局 : 问题
Tk.formlayout(ei, "选择标的:")
Tk.formlayout(e, "tradeDate:")
Tk.formlayout(rb,"复盘选择")
Tk.formlayout(b, nothing)
Tk.formlayout(txt,"tradeFlows")
#pack(txt, expand=true, fill="both")
Tk.formlayout(sc,nothing)
Tk.grid(sc, 5:20,200,sticky="news")  # 设定滚动条的位置
#grid(Slider(f, 1:10), 1  , 2:3, sticky="news")
Tk.focus(e)            ## put keyboard focus on widget
currentTrade ="" ;
nextDay = Dates.Date(2000,1,1)
function callback(path)
instrument =  uppercase(get_value(ei))
# pData :Dict{Date,Array{kBarData,1}}();
!isdefined(:totalDictDictDictData_NMin) && error("totalDictDictDictData_NMin is not exist!")
if haskey(totalDictDictDictData_NMin,instrument)
pData  =  StrategyData.getMainContractContinousData(totalDictDictDictData_NMin,instrument)
else
msg =string("数据中不包含这个标的: ",instrument,"!")
Tk.Messagebox(f,  msg)
end
tradeDates = sort(collect(keys(pData)))
p      = Winston.FramedPlot(height=200,width=400);
val    = get_value(e)
dateStr= split(val,"-");
yyear  = parse(Int64,dateStr[1]);
mmonth = parse(Int64,dateStr[2]);
dday   = parse(Int64,dateStr[3])
ddate  = Dates.Date(yyear,mmonth,dday);
#currentTrade =string("复盘策略: ",strategyName, "   复盘日期:",string(ddate),"\n");
currentTrade =string( "   复盘日期:",string(ddate),"\n");
totalPL = 0.0;
nextDay = ddate;
if get_value(rb)=="向后复盘"
if  !haskey(pData,ddate)
for i =1:length(tradeDates)
if tradeDates[i]>ddate
ddate =tradeDates[i];
break;
end
end
msg ="此日不是交易日!自动转移动下一个最近交易日!"
Tk.Messagebox(f, msg)
end

for i =1:length(tradeDates)
if tradeDates[i] > ddate
nextDay =tradeDates[i];
break;
end
end
if nextDay==ddate
msg ="已到最后交易日!"
Tk.Messagebox(f, msg)
end
else
if  !haskey(pData,ddate)
for i =length(tradeDates):-1:1
if tradeDates[i]<ddate
ddate =tradeDates[i];
break;
end
end
msg ="此日不是交易日!自动转移动上一个最近交易日!"
Tk.Messagebox(f,  msg)
end

for i =length(tradeDates):-1:1
if tradeDates[i]<ddate
nextDay =tradeDates[i];
break;
end
end
if nextDay==ddate
msg ="已到第一个交易日!"
Tk.Messagebox(f,  msg)
end
end
#println(currentTrade);
#println(string(nextDay));
# 找到下一个交易日时间

tradeData = pData[ddate]
contract  = tradeData[1].Code;
#setattr(p,draw_nothing=true);
# 今天交易流水
series =0;
currentFlow=tradeFlow[];
currSortFlows =tradeFlow[];
# 交易明细部分  : 有顺序地输出交易流水
for i =1: length(tradeFlows)
if Dates.Date(tradeFlows[i].openDate)==ddate
push!( currentFlow,tradeFlows[i])
end
end

if !isempty( currentFlow)
curOpenTime=DateTime[];
for flow in  currentFlow
if !in(flow.openDate,curOpenTime) # 保证不重复
push!(curOpenTime,flow.openDate)
end
end
sort!(curOpenTime) #排序
# 把当天的交易按开仓时间顺序排列好
for dt in curOpenTime
for flow in  currentFlow
if flow.openDate==dt
push!(currSortFlows,flow)
end
end
end
for flow in currSortFlows
series =series+1;
oTime =Dates.hour(flow.openDate)*100+Dates.minute(flow.openDate)
if oTime>=1000
openTime =string(oTime);
else
openTime =string("0",string(oTime))
end
openPrice =string(flow.openPrice);
if length(openPrice)>7
openPrice =openPrice[1:7]
end
cTime =Dates.hour(flow.closeDate)*100+Dates.minute(flow.closeDate)
if cTime>=1000
closeTime =string(cTime);
else
closeTime =string("0",string(cTime))
end
closePrice =string(flow.closePrice);
if length(closePrice)>7
closePrice =closePrice[1:7]
end
if flow.tradeType >0
PL =flow.closePrice-flow.openPrice;
direction ="L   "
else
PL =-flow.closePrice+flow.openPrice;
direction ="S   "
end
totalPL =totalPL+PL;
strPL =@sprintf("%0.1f",PL)
str0 ="---------------------------------------"
str1 =string("\n","第  ",string(series)," 次交易 =>   ",  flow.strategyName, "   \n" )
str2 =string("开仓方向 : ",direction   , "       此笔盈亏 :   ", strPL      ,"   \n")
str3 =string("开仓时间 : ", openTime, "       开仓价格 :   ",openPrice,"   \n")
str4 =string("平仓时间 : ", closeTime, "       平仓价格 :   ",closePrice,"   \n")
tempString =string(str0,str1,str2,str3,str4);
currentTrade =string( currentTrade,tempString);
end
end

strTotalPL =@sprintf("%0.1f",totalPL) # 总盈亏
currCount  =length(currentFlow);
# 画图
Winston.setattr(p,title=string("复盘日期:", val,"  ","   复盘标的: ",contract,   "   复盘策略:", strategyName));
Winston.setattr(p,title=string("复盘日期:", val,"  ","   复盘标的: ",contract,"  当日开仓次数:",currCount,"  累计盈亏:",strTotalPL ));
#x =[ hour(tradeData[i].DateTime)*100+minute(tradeData[i].DateTime) for i =1:length(tradeData)]; # 横坐标,时间
y =Float64[];
for i=1: length(tradeData)
push!(y,tradeData[i].Close)
end
x =Int64[];
for i=1:length(tradeData)
push!(x,i);
end
Winston.add(p,Curve(x,y))
# 交易总结
if !isempty(currentFlow)
for i=1: length(currentFlow)
opTime  =  Dates.hour(currentFlow[i].openDate)*100+Dates.minute(currentFlow[i].openDate);
clTime  =  Dates.hour(currentFlow[i].closeDate)*100+Dates.minute(currentFlow[i].closeDate);
LS      =  currentFlow[i].tradeType;
for j=1: length(tradeData)
mkTime = Dates.hour(tradeData[j].DateTime)*100+Dates.minute(tradeData[j].DateTime);
if mkTime==opTime
buyP = Winston.Points(j,tradeData[j].Close*0.995,kind="filled circle",color="red")
# if LS>0
#Winston.setattr(buyP, ticklabels=["OpenBuy"])
#else
#Winston.setattr(buyP, ticklabels=["OpenSell"])
# end
Winston.add(p,buyP);
elseif mkTime ==clTime
sellP = Winston.Points(j,tradeData[j].Close*1.005,kind="filled circle",color="green");
Winston.add(p,sellP)
end
end
end
totalStr1 =string("\n","---------------------------------------","\n")
totalStr2 =string("当日交易总次数:   ", currCount, "   总盈亏:    ", strTotalPL,"\n")
totalStr  =string(totalStr1,totalStr2)
currentTrade =string(currentTrade,totalStr)
else
totalStr1 =string("---------------------------------------","\n")
currentTrade =string(currentTrade,totalStr1,"今日策略无交易!")
end
# 更新相应控件的信息
Tk.set_value(e,string(nextDay));
Tk.set_value(txt,currentTrade);
# 打点,进入点,退出点,一根直线  补充!
Winston.display(p)
#hold(true)
end
Tk.bind(b, "command", callback)
Tk.bind(b, "<Return>", callback)
Tk.bind(txt,"<Return>", callback)
Tk.bind(e, "<Return>", callback)
Tk.bind(ei, "<Return>", callback)
Tk.bind(sc,"<Return>", callback)


效果图:



改进1

关于箭头:

我用PyPlot库重新写了一遍,已经有了较大改进:



关于callback函数改写,没办法,动力不足,懒……。

现在的函数太长,最好要拆成多个小函数的组合。这个主要怪我有点懒。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: