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也是可以的,我也试过。
代码如下:
效果图:
改进1
关于箭头:
我用PyPlot库重新写了一遍,已经有了较大改进:
关于callback函数改写,没办法,动力不足,懒……。
现在的函数太长,最好要拆成多个小函数的组合。这个主要怪我有点懒。
特点: 纯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函数改写,没办法,动力不足,懒……。
现在的函数太长,最好要拆成多个小函数的组合。这个主要怪我有点懒。
相关文章推荐
- 基于JDBC的数据库连接池高效管理策略
- 基于策略路由的IP地址控制
- 基于递归策略的排序算法
- 基于策略的一种高效内存池的实现
- 基于番茄土豆的scrum工时估计方法尝试
- Cisco 路由器 基于时间控制策略案例
- quick-cocos2d-x基于源码加密打包功能的更新策略(1)
- 第十八章——基于策略的管理(1)——评估数据库属性
- 基于Matlab和Wind SQL数据库的通用选股策略回测程序
- 设计一个基于用户的API限流策略 Rate Limit
- 基于Android设计模式之--SDK源码之策略模式的详解
- 基于Linux核心的汉字显示的尝试
- 基于WGS和CBC测序策略的DNA序列拼接算法研究(四)
- 彻底弄懂 Http 缓存机制 - 基于缓存策略三要素分解法
- 彻底弄懂 Http 缓存机制 - 基于缓存策略三要素分解法
- 基于管道共享的流控策略(2)
- hibernate主键生成策略(基于Annotation)
- quick-cocos2d-x基于源码加密打包功能的更新策略(1) (转)
- 分析基于ASP.NET的Web网络应用程序开发的平安策略实践
- 乐观的并发策略——基于CAS的自旋