FAQ > 金融建模 > 应用案例 > 回测应用

Q:如何实现股票的T+0回测?    

  • A:国内市场规则本身是不支持部分证券资产(比如:股票,ETF等)的T+0交易的,在天软的回测框架中通过设置部分成员变量可以实现T+0回测,
    目前实现T+0回测需满足以下条件
    1.组合类型选择数量类回测,即成员变量FGroupType=2;
    2.数量类组合开仓数量类别选择固定成交量法,即成员变量FOpenVolType=1;
    3.数量类组合平仓数量类别选择固定成交量法,即成员变量FCloseVolType=1;
    4.设置可以日内平仓,即成员变量FNoT0 = 1;
    5.不能设置不允许超卖,即成员变量FNoOverSold取默认值0。
    实现示例
    {
      回测说明:以昨日涨停股为股池,回测期间持有5个股票,买入后若当天跌幅超过2%则卖出,并从股池中购入新股
      注:1.回测期间已购买过的股票不在重复购买;
        2.股池剔除st股
    }
      begt:=20251101t;
      endt:=20251125t;
      obj := createobject('HighFrequencyT0Trading');
      //********************回测基本设置***************************//
      //回测开始时间
      obj.FBegT:=BegT;
      //回测截止时间
      obj.FEndT:=EndT;
      //回测周期
      obj.FCycle:=cy_1m();
      // 回测初始资金
      obj.FIniCash := 1000000;
      
      //组合类型(数量类组合)
      obj.FGroupType:=2;
      //成交价类别(自定义价格)
      obj.FPriceType:=-1;
      //数量类组合开仓数量类别(此处采用固定成交量法)
      obj.FOpenVolType:=1;
      //数量类组合平仓数量类别(此处采用固定成交量法)
      obj.FCloseVolType:=1;
      // 可以日内平仓
      obj.FNoT0 := 1;


      //最大持有数量
      obj.FMaxN := 5;
      //记录已买过的的票
      obj.Fdelstocks := array();

      //回测
      obj.BackTest();
      //获取返回结果(返回结果可根据需要选择)
      return array(
         //---组合基础
        "交易明细":obj.GetTradeData(BegT,EndT),
        "资产配置":obj.GetAssetData(BegT,EndT),
        "持仓明细":obj.GetHoldData(BegT,EndT),

         //---组合盈亏、交易
        "组合盈亏":obj.GetGainandLoss(BegT,EndT),
        "交易汇总":obj.GetTradingAmount(BegT,EndT),
        "组合盈亏(按证券)":obj.GetGainandLossBySecurity(BegT,EndT),
        "交易汇总(按证券)":obj.GetTradingAmountBySecurity(BegT,EndT),

         //---组合收益
        "区间组合收益率": obj.GetPortfolioReturn(BegT,EndT),
        "组合和基准收益率序列":obj.GetPortfolioReturn2(BegT,EndT),
        "阶段收益":obj.GetTrailingReturn(EndT),
        "滚动收益":obj.GetRollingReturn(BegT,EndT,cy_month()),

        //----组合评价
        "风险回报":obj.GetReturnandRisk(BegT,EndT),
        "相对回报":obj.GetRelativePerformance(BegT,EndT),
        );

    Type HighFrequencyT0Trading=class(TSBackTesting)
      FMaxN;  //最大持有股票数
      Fdelstocks; //已买过的的票不再购买

      function GetTradeOrder(vEndT);override;
      begin
        oV := BackupSystemParameters2();
        setsysparam(pn_cycle(),FCycle);
         //当前时间
        d := vEndT;
        d0:=specall(LastTradeDay(d),array(pn_stock():"SH000001",pn_cycle():cy_day()));
        echo datetimetostr(d);
        cc := GetHoldData(); //获取当前持仓
        cash := GetSurplusFund(); //获取剩余资金

        ccstocks := sselect distinct(['代码']) from cc end; //获取持仓中的股票代码
        Fdelstocks union2=ccstocks;
        tjy := array();
        n:=0;
        if istable(ccstocks) then
          ccnum := length(ccstocks)
        else
          ccnum := 0;
        newccnum := ccnum;
        if newccnum<FMaxN then //当前持仓股票个数小于最大持仓数
        begin
          stockArr:=sselect thisrow from GetAbkbyDate("A股",d0) where spec(StockIsZt(d0),thisrow) and not spec(IsST_3(d0),thisrow) end;
          //判断开仓
          for nI:=0 to length(StockArr)-1 do
          begin
            stockid := StockArr[nI];
            setsysparam(pn_stock(),stockid);
            setsysparam(pn_date(),d);
            if not istradeday(d) then continue;
            if not (stockid in Fdelstocks) then //已买过的的票不再购买
            begin
              tjy[n]['截止日'] := d;
              tjy[n]['代码'] := stockid;
              tjy[n]['名称'] := stockname(stockid);
              tjy[n]['方向'] := 1;
              tjy[n]['动作'] := 0;
              tjy[n]['成交价']:= close();
              tjy[n]['成交量'] := cash/(FMaxN-ccnum)/close();
              n++;
              newccnum++;
            end
            if newccnum>=FMaxN then break; //当持仓的证券个数大于最大持仓个数就终止开仓
          end
        end;

         //平仓,对持仓循环判断是否达到平仓条件,当天涨幅小于2%平仓
        for nJ:=0 to length(cc)-1 do
        begin
          stockid := cc[nJ]['代码'];
          setsysparam(pn_stock(),stockid);
          setsysparam(pn_date(),d);
          zf:=stockzf6(dateof(d),d);
          if zf<-2 then
          begin
            tjy[n]['截止日']:= d;
            tjy[n]['代码'] := stockid;
            tjy[n]['名称'] := stockname(stockid);
            tjy[n]['方向'] := 1;
            tjy[n]['动作'] := 1;
            tjy[n]['成交价']:= close();
            tjy[n]['成交量'] :=cc[nJ]["数量"];
            n++;
          end
        end;

        return tjy;
      end
    End;

    回测结果:

    部分T+0交易明细: