资源加载中... loading...

手把手教你写策略--移植一个my语言策略

Author: 发明者量化-小小梦, Created: 2019-10-21 14:59:12, Updated: 2024-12-17 20:37:18

手把手教你写策略–移植一个my语言策略

手把手教你写策略–移植一个my语言策略

最近和朋友聊策略的时候,了解到有不少使用my语言编写策略苦于灵活的问题。很多情况下需要使用非系统提供的标准K线周期,例如提出最多的就是需求使用4小时K线。这个问题已经在一篇文章中得以解决,有兴趣的可以先看下:链接。不过在my语言策略中这个问题由于my语言高度的封装特性,无法灵活的自行处理数据。这个时候就需要把策略思路移植为其它语言。

对于趋势策略移植来说是非常简单的,我们可以使用一段范例代码,填充驱动策略的数据计算部分代码,填充交易信号触发条件即可。

可复用的范例代码:

以用于OKEX期货的策略为例。

  // 全局变量
  var IDLE = 0
  var LONG = 1
  var SHORT = 2
  var OPENLONG = 3
  var OPENSHORT = 4
  var COVERLONG = 5
  var COVERSHORT = 6  

  var BREAK = 9
  var SHOCK = 10  

  var _State = IDLE
  var Amount = 0                 // 记录持仓数量
  var TradeInterval = 500        // 轮询间隔
  var PriceTick = 1              // 价格一跳
  var Symbol = "this_week"  

  function OnTick(){
      // 驱动策略的行情处理部分
      // 待填充...
       
      // 交易信号触发处理部分
      // 待填充...  

      // 执行交易逻辑
      var pos = null
      var price = null
      var currBar = records[records.length - 1]
      if(_State == OPENLONG){
          pos = GetPosition(PD_LONG)
          // 判断是不是 满足状态,如果满足 修改状态
          if(pos[1] >= Amount){
              _State = LONG
              Amount = pos[1]   // 更新实际量
              return
          }
          price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
          Trade(OPENLONG, price, Amount - pos[1], pos, PriceTick)                // (Type, Price, Amount, CurrPos, PriceTick)
      }  

      if(_State == OPENSHORT){
          pos = GetPosition(PD_SHORT)
          if(pos[1] >= Amount){
              _State = SHORT
              Amount = pos[1]   // 更新实际量
              return
          }
          price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
          Trade(OPENSHORT, price, Amount - pos[1], pos, PriceTick)
      }  

      if(_State == COVERLONG){
          pos = GetPosition(PD_LONG)
          if(pos[1] == 0){
              _State = IDLE
              return
          }
          price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
          Trade(COVERLONG, price, pos[1], pos, PriceTick)
      }
      
      if(_State == COVERSHORT){
          pos = GetPosition(PD_SHORT)
          if(pos[1] == 0){
              _State = IDLE
              return
          }
          price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
          Trade(COVERSHORT, price, pos[1], pos, PriceTick)
      }
  }  

  // 交易逻辑部分
  function GetPosition(posType) {
      var positions = _C(exchange.GetPosition)
      var count = 0
      for(var j = 0; j < positions.length; j++){
          if(positions[j].ContractType == Symbol){
              count++
          }
      }  

      if(count > 1){
          throw "positions error:" + JSON.stringify(positions)
      }  

      for (var i = 0; i < positions.length; i++) {
          if (positions[i].ContractType == Symbol && positions[i].Type === posType) {
              return [positions[i].Price, positions[i].Amount];
          }
      }
      Sleep(TradeInterval);
      return [0, 0];
  }  

  function CancelPendingOrders() {
      while (true) {
          var orders = _C(exchange.GetOrders)
          for (var i = 0; i < orders.length; i++) {
              exchange.CancelOrder(orders[i].Id);
              Sleep(TradeInterval);
          }
          if (orders.length === 0) {
              break;
          }
      }
  }  

  function Trade(Type, Price, Amount, CurrPos, OnePriceTick){    // 处理交易
      if(Type == OPENLONG || Type == OPENSHORT){                 // 处理开仓
          exchange.SetDirection(Type == OPENLONG ? "buy" : "sell")
          var pfnOpen = Type == OPENLONG ? exchange.Buy : exchange.Sell
          var idOpen = pfnOpen(Price, Amount, CurrPos, OnePriceTick, Type)
          Sleep(TradeInterval)
          if(idOpen) {
              exchange.CancelOrder(idOpen)
          } else {
              CancelPendingOrders()
          }
      } else if(Type == COVERLONG || Type == COVERSHORT){        // 处理平仓
          exchange.SetDirection(Type == COVERLONG ? "closebuy" : "closesell")
          var pfnCover = Type == COVERLONG ? exchange.Sell : exchange.Buy
          var idCover = pfnCover(Price, Amount, CurrPos, OnePriceTick, Type)
          Sleep(TradeInterval)
          if(idCover){
              exchange.CancelOrder(idCover)
          } else {
              CancelPendingOrders()
          }
      } else {
          throw "Type error:" + Type
      }
  }  

  function main() { 
      // 设置合约
      exchange.SetContractType(Symbol)  

      while(1){
          OnTick()
          Sleep(1000)
      }
  }

举例:双均线策略的移植

麦语言回测: 手把手教你写策略–移植一个my语言策略

麦语言策略代码:

  MA5^^MA(C,5);
  MA15^^MA(C,15);
  CROSSUP(MA5,MA15),BPK;
  CROSSDOWN(MA5,MA15),SPK;

移植为JavaScript策略

首先给可复用的范例代码填充上行情获取、指标计算部分:

  // 驱动策略的行情处理部分
  var records = _C(exchange.GetRecords)  

  if (records.length < 15) {
      return 
  }  

  var ma5 = TA.MA(records, 5)
  var ma15 = TA.MA(records, 15)
  var ma5_pre = ma5[ma5.length - 3]
  var ma15_pre = ma15[ma15.length - 3]
  var ma5_curr = ma5[ma5.length - 2]
  var ma15_curr = ma15[ma15.length - 2]

可以看到,双均线策略非常简单,只是首先获取K线数据records,然后使用TA函数库的均线函数TA.MA计算出5日均线、15日均线(回测界面上可以看到,K线周期设置的是日K线,所以TA.MA(records, 5)计算出的就是5日均线,TA.MA(records, 15)15日均线)。 然后获取ma5指标数据的倒数第二个点ma5_curr(指标值),倒数第三个点ma5_pre(指标值),ma15指标数据同理。然后就可以使用这些指标数据去判断金叉死叉了,如图: 手把手教你写策略–移植一个my语言策略 只要形成这样的状态,即为确定的金叉死叉。

那么判断信号的部分就可以写成:

  if(_State == IDLE && ma5_pre < ma15_pre && ma5_curr > ma15_curr){     
      _State = OPENLONG
      Amount = 1
  }  

  if(_State == IDLE && ma5_pre > ma15_pre && ma5_curr < ma15_curr){     
      _State = OPENSHORT
      Amount = 1
  }  

  if(_State == LONG && ma5_pre > ma15_pre && ma5_curr < ma15_curr){     
      _State = COVERLONG
      Amount = 1
  }  

  if(_State == SHORT && ma5_pre < ma15_pre && ma5_curr > ma15_curr){     
      _State = COVERSHORT
      Amount = 1
  }

这样就移植OK了,可以回测试下: JavaScript策略的回测 回测配置: 手把手教你写策略–移植一个my语言策略

回测结果:
![手把手教你写策略--移植一个my语言策略](/upload/asset/16baa65d35e034e06a58.png) 

my语言的回测 手把手教你写策略–移植一个my语言策略

可以看到回测结果基本一样,这样如果希望对于策略继续增加交互功能、增加数据处理(例如K线合成)、增加自定义的图表画图显示就可以实现了。

有兴趣的同学动手试试吧


相关内容

更多内容

小强 学习下