开拓者期货期权程序化系统交易论坛

标题: 关于回溯测试和自动交易同步的处理 [打印本页]

作者: nopain    时间: 2007-9-13 22:20:57     标题: 关于回溯测试和自动交易同步的处理

最近,总有一些朋友问到如何编写公式代码,来处理测试和自动交易的资金、持仓及成交价等信息不匹配的问题。此问题是自动交易一个普遍存在的问题,因此,单独开贴进行讨论。

首先,我们需要理清几个概念:

回溯测试:(Back-Testing),将交易系统应用到历史数据当中,产生相应的买卖动作,并根据这些买卖动作产生详细的测试报表。

自动交易:将回溯测试在最新数据(图表中最后一个Bar)下产生的买卖讯号,应用到指定的帐号中,进行实时自动交易。

根据上面的叙述,我们可以得知,回溯测试在图表中最后一个Bar的讯号反映到交易账户中即自动交易,但是实际运行中,很多情况下用户不会完全按照交易指令的指示进行交易。这样就会出现真实交易时,通过回归测试产生的交易数量及价格并不是我们期望的。这个时候就需要我们通过编写公式代码进行控制,达到预期的效果。(最完美的处理方式是尽量让测试资金,持仓和真实情况一致,这样就不需要进行任何同步操作,以下的信息也都可以忽略啦

在需要处理的情况下,可分为开仓和平仓两种情况,以下分别进行讨论。
作者: nopain    时间: 2007-9-13 22:23:10     标题: 开仓的处理

开仓情况下,以多头买入为例:

在回溯测试中产生开仓买入的指令,然后将该指令应用到交易账户中,可能出现2种情况:
1、交易账户的资金和回溯测试的资金不匹配,此时我们应该按照交易帐户的资金量来进行开仓。
2、交易账户的持仓和回溯测试的持仓不匹配,此时我们应该考虑是进行仓位同步,还是忽略该买入操作。
大致的处理代码如下:
  1. If(BuyCondition) // 买入开仓条件满足
  2. {
  3.     lots = ...;       // 回溯测试计算出的交易数量
  4.     entryPrice = ...; // 回溯测试计算出的交易价格
  5.    
  6.     If(BarStatus == 2) // 当前Bar为最后的一个Bar
  7.     {
  8.         lots = (A_FreeMargin*0.2)/(Q_AskPrice*ContractsUnit*BigPointValue*MarginRatio); // 假定按照可用资金的20%开仓
  9.         lots = IntPart(lots);   // 取整
  10.         entryPrice = Q_AskPrice;        // 按当时的叫卖价买入
  11.         
  12.         If(CurrentContracts()!=A_TotalPosition()) // 回溯测试的仓位和真实仓位不一致
  13.         {
  14.             // 根据您的需要进行处理,A_TotalPosition是合计的仓位,可通过A_BuyPosition,A_SellPosition取出买卖持仓.
  15.         }              
  16.         Buy(lots,entryPrice);
  17.     }else
  18.     {
  19.         Buy(lots,entryPrice);   // 回溯测试的其他Bar直接买入
  20.     }
  21. }
复制代码

[ 本帖最后由 nopain 于 2007-9-14 10:36 编辑 ]
作者: nopain    时间: 2007-9-14 13:42:54     标题: 平仓的处理

平仓的情况,以多头卖出为例:

在回溯测试中产生平仓买出的指令,然后将该指令应用到交易账户中,可能出现2种情况:
1、交易账户的持多仓不足,或者是持有空仓。这个时候我们可以是平掉不足的多仓,也可以选择忽略该平仓操作,还可以平掉空仓。
2、交易账户的持多仓比回溯测试要平的多,这个时候我们可以选择只平测试讯号产生的部分,也可以全部平掉。

大致的处理代码如下:
  1. If(SellCondition) // 卖出平仓条件满足
  2. {
  3.     lots = ...;      // 回溯测试计算出的交易数量
  4.     exitPrice = ...; // 回溯测试计算出的交易价格
  5.    
  6.     If(BarStatus == 2) // 当前Bar为最后的一个Bar
  7.     {      
  8.         exitPrice = Q_BidPrice; // 用当时的叫买价卖出
  9.         
  10.         If(CurrentContracts()!=A_TotalPosition()) // 回溯测试的仓位和真实仓位不一致
  11.         {
  12.             // 根据您的需要进行处理,A_TotalPosition是合计的仓位,可通过A_BuyPosition,A_SellPosition取出买卖持仓.
  13.         }
  14.         
  15.         If(A_BuyPosition >= lots)
  16.         {
  17.             Sell(lots,exitPrice);
  18.         }
  19.     }else
  20.     {
  21.         Sell(lots,exitPrice);   // 回溯测试的其他Bar直接卖出
  22.     }
  23. }
复制代码

作者: 柳长街    时间: 2007-9-14 15:15:56

我最想知道的是怎样把买卖信号产生后在我的交易软件上实施成交,谢谢
作者: nopain    时间: 2007-9-14 15:26:30

原帖由 柳长街 于 2007-9-14 15:15 发表
我最想知道的是怎样把买卖信号产生后在我的交易软件上实施成交,谢谢


你用交易开拓者做单不就可以啦!
作者: 柳长街    时间: 2007-9-14 15:50:07

原帖由 nopain 于 2007-9-14 15:26 发表


你用交易开拓者做单不就可以啦!



呵呵,不知道我在交易开拓者做单赚的钱你什么时候给我啊?给十分之一也行啊,其余的算是给您的回扣
作者: nopain    时间: 2007-9-14 16:05:15

原帖由 柳长街 于 2007-9-14 15:50 发表



呵呵,不知道我在交易开拓者做单赚的钱你什么时候给我啊?给十分之一也行啊,其余的算是给您的回扣


早点用开拓者做实盘不就赚大发了
作者: skyline    时间: 2007-9-27 19:05:41

怎么进行回溯测试?

好像TB没有这个选项
作者: nopain    时间: 2007-9-27 21:21:03

原帖由 skyline 于 2007-9-27 19:05 发表
怎么进行回溯测试?

好像TB没有这个选项


您的回溯测试是指什么?重放么,那是没有。
用模拟账户交易进行系统测试吧。
作者: skyline    时间: 2007-9-28 16:04:40

对的,我指重放。
像MTTrader那样
作者: 孤舟骑浪    时间: 2007-12-21 16:55:06     标题: 提问题

有两个问题:
1、当前最后一个bar历史回溯中开仓条件满足,执行真实帐户的开仓操作,图上应该还没出现交易指令产生的买入标志,当新的bar出现时,刚才的bar是否还会重画历史回溯测试产生的开仓标志?如果重画,是不是程序按每tick都会从currentbar==0起再执行一次,如果是这样,一切都可以理解了。
2、A_SellPosition是一个正数还是负数?
作者: 孤舟骑浪    时间: 2007-12-21 20:22:46

  1. if(根据图表产生开仓条件)
  2. {
  3.    If(AccountDataExist and barstatus==2 and A_TotalPosition==0)
  4.      {
  5.         oneMargin = Q_Last*ContractUnit()*BigPointValue()*MarginRatio();
  6.         TotalEquity=A_FreeMargin;
  7.          lots = IntPart((TotalEquity*EntryRatio)/oneMargin);
  8.          myEntryprice=Q_AskPrice;
  9.          buy(lots,myEntryprice);
  10.     }Else
  11.     {       
  12.          oneMargin = low*ContractUnit()*BigPointValue()*MarginRatio();
  13.         TotalEquity = CurrentCapital()+ Abs(CurrentContracts())*oneMargin;
  14.          lots = IntPart((TotalEquity*EntryRatio)/oneMargin);
  15.          buy(lots,low);
  16.          setglobalvar(0,low);
  17.          commentary("此次开仓价为:"+text(low));
  18.    }
  19. }
复制代码

帮看一下上面的代码是否达到了同步的目的?开仓标志是否可以比实际帐户发出委托并成交后稍迟一点也出现在最后一根bar上?
作者: tradeblazer    时间: 2007-12-21 22:21:59

原帖由 孤舟骑浪 于 2007-12-21 16:55 发表
有两个问题:
1、当前最后一个bar历史回溯中开仓条件满足,执行真实帐户的开仓操作,图上应该还没出现交易指令产生的买入标志,当新的bar出现时,刚才的bar是否还会重画历史回溯测试产生的开仓标志?如果重画,是不是程序按每tick ...


1、对最后一个Bar上真实账户交易,如果用Buy,Sell等函数写的交易动作,会在图上产生讯号。当这个Bar变成倒数第二个Bar时,它仍然会被执行一次(不是从头开始算,只计算最后1个或2个Bar)。这个时候就会执行(BarStatus!=2)的分支,然后数量和价格也许会产生些许变化,但讯号应该还在。我们写代码时需要达到这样的效果,否则就会出现问题。
2、正数。
作者: tradeblazer    时间: 2007-12-21 22:23:10

原帖由 孤舟骑浪 于 2007-12-21 20:22 发表
if(根据图表产生开仓条件)
{
   If(AccountDataExist and barstatus==2 and A_TotalPosition==0)
     {
        oneMargin = Q_Last*ContractUnit()*BigPointValue()*MarginRatio();
        TotalEquity=A_FreeMar ...


不能这么写,最好在条件的最外层放BarStatus的判断。
作者: 孤舟骑浪    时间: 2007-12-22 09:26:55

  1. if(根据图表产生开仓条件)
  2. {
  3.    If(barstatus==2)
  4.      {
  5.         oneMargin = Q_Last*ContractUnit()*BigPointValue()*MarginRatio();
  6.         TotalEquity=A_FreeMargin;
  7.          lots = IntPart((TotalEquity*EntryRatio)/oneMargin);
  8.          myEntryprice=Q_AskPrice;
  9.          buy(lots,myEntryprice);
  10.     }Else
  11.     {        
  12.          oneMargin = low*ContractUnit()*BigPointValue()*MarginRatio();
  13.         TotalEquity = CurrentCapital()+ Abs(CurrentContracts())*oneMargin;
  14.          lots = IntPart((TotalEquity*EntryRatio)/oneMargin);
  15.          buy(lots,low);
  16.          setglobalvar(0,low);
  17.          commentary("此次开仓价为:"+text(low));
  18.    }
  19. }
复制代码

根据nopain前面的实例,这段程序只要删掉一些条件内容就和实例差不多了,如上,应该可以了吧.
根据tradeblazer的描述,原来是当真实帐户产生交易时,在最后一个bar会产生开仓讯号并且开仓数量和真实帐户所开仓数一致,当开仓的bar变为倒数第二根bar时,倒数第二根bar会执行一次分枝条件,重新计算测试帐户的价格和开仓数量,并且重画开仓讯号,就是这样理解了.
作者: 孤舟骑浪    时间: 2007-12-24 10:29:40

现在是达到了测试和实盘同步了,只是首次开仓讯号的开仓数量与真实帐户并不同,变为倒数第二根后,才调整回正常的数值,不过已不伤大雅了.正在偷笑中
作者: jvya    时间: 2008-1-23 11:39:04

我不能理解这句
exitPrice = Q_BidPrice; // 用当时的叫买价卖出
、、、
、、、
Sell(lots,exitPrice);


exitPrice 函数,获得最近平仓位置的平仓价格。那应该是已经平仓结束之后的取出平仓的值
exitPrice = Q_BidPrice; 这句看起来是把他当作一个变量进行赋值了。


exitPrice = Q_BidPrice; // 用当时的叫买价卖出
、、、
、、、
Sell(lots,exitPrice);
这样,好似看起来是,在没平仓之前 ,抢先给函数赋值。
我看着有点晕。
帮着解释一下吧。
作者: tradeblazer    时间: 2008-1-23 11:53:00

不能用exitPrice作为变量吧。已经是系统函数了
应该是myExitprice吧。
作者: jvya    时间: 2008-1-23 14:09:19

是的啊,
我也觉得应该是这样的
谢了
作者: wg3k99    时间: 2008-1-23 22:37:23

好,很好,非常好,希望有一天能把这些问题,整理出来,编成CHM文件,或者编成一本书
作者: 孤舟骑浪    时间: 2008-1-24 09:45:22     标题: 请教问题

在交易函数中AvgEntryPrice()对应帐户函数的A_buyavgprice和A_sellavgprice,请问exitprice对应帐户函数的什么函数,如果没有这一函数,应如何达到类似目的,获取帐户的最后平仓价?
我曾试过如下处理,但依然未达到效果:
  1.                                                         if(barstatus==2)
  2.                                                         {       
  3.                                                                
  4.                                                                 lots=A_BuyPosition;
  5.                                                                 myExitprice=Q_BidPrice;
  6.                                                                 SetGlobalVar(1,lots);
  7.                                                                 sell(lots,myExitprice);
  8.                                                                 if(j<1)
  9.                                                                 {
  10.                                                                 setglobalvar(0,myExitprice);
  11.                                                                 }
  12.                                                                 j=j+1;
  13.                                                         }Else{回测平仓代码...}
复制代码

作者: tradeblazer    时间: 2008-1-24 10:18:15

没有对应的函数
按现在的结算方式及架构基本上是不可能做到的
作者: lowfi    时间: 2008-4-25 10:30:34

找了好久.建议斑竹置顶.
作者: PYZFL    时间: 2008-11-14 15:25:14

楼主,有个很简单的交易策略,但在使用时既不能显示交易信号,也不能进行交易,为什么?您能帮我测试一下吗?

Params
        Numeric DkFj(5);       
Vars

        NumericSeries LineDkFj;       
Begin
        LineDkFj = AverageFC(close,DkFj);       
       
        If(CrossOver(Close,LineDkFj))
        {
                If(BarStatus == 2) // 当前Bar为最后的一个Bar
                        Buy(4 -A_BuyPosition ,close,True);
                Else
                        Buy(4,close,True);
        }
        If(CrossUnder(Close,LineDkFj))
        {
                If(BarStatus == 2) // 当前Bar为最后的一个Bar
                        Sell(4 -A_BuyPosition ,close,True);
                Else
                        Sell(4,close,True);
        }
       
End
作者: ccms    时间: 2009-9-8 21:05:15

对于这个问题,现如今有没有更好滴办法。
作者: ccms    时间: 2009-9-8 22:13:20

NOPAIN速看-----------------------------------------》http://www.tradeblazer.net/forum/thread-5448-1-1.html
作者: chinaif    时间: 2011-8-11 09:37:03

校验的时间是个主要问题,处理不好就是制造出新的问题。效率不高,很纠结。
作者: Amymylove    时间: 2011-9-30 13:43:45

马克留名学习之
作者: 文刀    时间: 2013-5-16 11:20:11

nopain 发表于 2007-9-13 22:23
开仓情况下,以多头买入为例:

在回溯测试中产生开仓买入的指令,然后将该指令应用到交易账户中,可能出现 ...

那个ContractsUnit说没有这个关键字啊,那是啥意思?




欢迎光临 开拓者期货期权程序化系统交易论坛 (http://bbs.tb18.net/) Powered by Discuz! X2