目前不清退的交易所推荐:

1、全球第二大交易所OKX欧意

国区邀请链接: https://www.myts3cards.com/cn/join/1837888   币种多,交易量大!

国际邀请链接:https://www.okx.com/join/1837888 注册简单,交易不需要实名,新用户能开合约,币种多,交易量大!

2、老牌交易所比特儿现改名叫芝麻开门 :https://www.gate.win/signup/649183

全球最大交易所币安,国区邀请链接:https://accounts.binance.com/zh-CN/register?ref=16003031  币安注册不了IP地址用香港,居住地选香港,认证照旧,邮箱推荐如gmail、outlook。支持币种多,交易安全!

买好币上KuCoin:https://www.kucoin.com/r/af/1f7w3  CoinMarketCap前五的交易所,注册友好操简单快捷!

FMZ量化交易平台邀请链接:https://www.fmz.com/

数字货币期货类马丁策略设计

最近FMZ官方群里讨论马丁类型的策略比较多,平台上关于数字货币合约的马丁策略不多。所以,借此机会设计了一个简单的数字货币期货类马丁策略。为什么说是类马丁策略,因为马丁策略潜在风险确实不小,就没有完全按照马丁策略去设计。但是这类策略依然是有不小的风险的,并且马丁类型的策略参数设置和风险息息相关,对于风险是千万不能忽视的。

本篇文章主要从马丁类型策略的设计上讲解学习,策略思路本身已经很明了,作为FMZ的使用者我们更多考虑策略设计。

获取总权益

在设计数字货币期货策略时,经常要用到总权益这个数据。因为要计算收益,特别是需要计算浮动收益时。由于持仓占用保证金,挂单也占用。这个时候调用FMZ平台的API接口exchange.GetAccount()获取的是可用资产和挂单冻结资产。其实大部分数字货币期货交易所都提供了总权益这个数据,只不过FMZ上没有统一封装这个属性。

所以我们根据不同的交易所分别设计函数获取这个数据:

// OKEX V5 获取总权益
function getTotalEquity_OKEX_V5() {
    var totalEquity = null 
    var ret = exchange.IO(\"api\", \"GET\", \"/api/v5/account/balance\", \"ccy=USDT\")
    if (ret) {
        try {
            totalEquity = parseFloat(ret.data[0].details[0].eq)
        } catch(e) {
            Log(\"获取账户总权益失败!\")
            return null
        }
    }
    return totalEquity
}

// 币安期货
function getTotalEquity_Binance() {
    var totalEquity = null 
    var ret = exchange.GetAccount()
    if (ret) {
        try {
            totalEquity = parseFloat(ret.Info.totalWalletBalance)
        } catch(e) {
            Log(\"获取账户总权益失败!\")
            return null
        }
    }
    return totalEquity
}

代码中totalEquity就是我们需要的总权益。然后我们再写个函数作为调用入口,根据交易所名称去具体调用对应的函数。

function getTotalEquity() {
    var exName = exchange.GetName()
    if (exName == \"Futures_OKCoin\") {
        return getTotalEquity_OKEX_V5()
    } else if (exName == \"Futures_Binance\") {
        return getTotalEquity_Binance()
    } else {
        throw \"不支持该交易所\"
    }
}

设计一些辅助函数

在设计主函数、主要逻辑之前。我们还需要做一些准备,设计一些辅助功能的函数。

  • 取消当前所有挂单
    function cancelAll() {
        while (1) {
            var orders = _C(exchange.GetOrders)
            if (orders.length == 0) {
                break
            }
            for (var i = 0 ; i < orders.length ; i++) {
                exchange.CancelOrder(orders[i].Id, orders[i])
                Sleep(500)
            }
            Sleep(500)
        }
    }
    

    这个函数相信经常看FMZ策略广场上策略范例代码的都很熟悉,很多策略都用过类似的设计。作用就是获取当前挂单列表,然后逐个撤销。

  • 期货的下单操作
    function trade(distance, price, amount) {    var tradeFunc = null     if (distance == \"buy\") {        tradeFunc = exchange.Buy    } else if (distance == \"sell\") {        tradeFunc = exchange.Sell    } else if (distance == \"closebuy\") {        tradeFunc = exchange.Sell    } else {        tradeFunc = exchange.Buy    }    exchange.SetDirection(distance)    return tradeFunc(price, amount)}function openLong(price, amount) {    return trade(\"buy\", price, amount)}function openShort(price, amount) {    return trade(\"sell\", price, amount)}function coverLong(price, amount) {    return trade(\"closebuy\", price, amount)}function coverShort(price, amount) {    return trade(\"closesell\", price, amount)}

    期货交易有四个方向:开多仓(openLong)、开空仓(openShort)、平多仓(coverLong)、平空仓(coverShort)。所以我们设计了四个下单函数对应这些操作。如果只考虑下单,那么有这样几个必要的因素:方向、下单价格、下单量。
    所以我们还设计了一个名为:trade的函数来处理当方向(distance)下单价格(price)下单量(amount)都明确时的操作。
    开多仓(openLong)、开空仓(openShort)、平多仓(coverLong)、平空仓(coverShort)这些函数调用最终都由trade函数完成实际功能,也就是根据既定的方向、价格、数量在期货交易所下单。

主函数

策略思路很简单,以当前价格为基线上下一定距离挂卖出(做空)、买入单(做多)。一边成交了就取消剩下的所有订单,然后根据持仓的价格在一定距离挂出新的平仓订单,在更新后的当前价格挂出加仓订单,但是加仓订单不加倍下单量。

  • 初始工作
    因为要挂单,所以我们需要两个全局变量记录订单ID。

    var buyOrderId = null
    var sellOrderId = null
    

    然后策略界面参数里设计了使用OKEX_V5模拟盘的选项,所以代码里要做一些处理:

    var exName = exchange.GetName()    
    // 切换OKEX V5模拟盘
    if (isSimulate && exName == \"Futures_OKCoin\") {
        exchange.IO(\"simulate\", true)
    }
    

    界面参数里还设计了重置所有信息的选项,所以代码里也要有对应的处理:

    if (isReset) {
        _G(null)
        LogReset(1)
        LogProfitReset()
        LogVacuum()
        Log(\"重置所有数据\", \"#FF0000\")
    }
    

    我们只跑永续合约,所以这里写死了,只设置为永续合约。

    exchange.SetContractType(\"swap\")
    

    然后我们还要考虑到下单价格精度、下单量精度的问题,如果精度不设置好,策略计算过程中精度丢失,数据的小数位很多的话容易引起下单时被交易所接口拒绝。

    exchange.SetPrecision(pricePrecision, amountPrecision)
    Log(\"设置精度\", pricePrecision, amountPrecision)
    

    设计上简单的数据恢复功能

    if (totalEq == -1 && !IsVirtual()) {
        var recoverTotalEq = _G(\"totalEq\")
        if (!recoverTotalEq) {
            var currTotalEq = getTotalEquity()
            if (currTotalEq) {
                totalEq = currTotalEq
                _G(\"totalEq\", currTotalEq)
            } else {
                throw \"获取初始权益失败\"
            }
        } else {
            totalEq = recoverTotalEq
        }
    }
    

    如果想在策略运行时指定最初账户总权益,可以设置参数totalEq,如果该参数设置为-1,策略会读取储存的总权益数据,如果没有储存的总权益数据,就是以当前读取的总权益作为策略运行进度的最初总权益,之后总权益增加就说明赚了,总权益少了就说明亏了。如果读取到总权益数据,则使用这个数据继续运行。

  • 主要逻辑
    初始工作做完之后,终于来到了策略主要逻辑的部分了,为了方便讲解,我直接把说明写在代码注释上了。

      while (1) {                                  // 策略主要逻辑设计为一个死循环
          var ticker = _C(exchange.GetTicker)      // 首先读取当前行情信息,主要用到最新成交价
          var pos = _C(exchange.GetPosition)       // 读取当前持仓数据
          if (pos.length > 1) {                    // 判断持仓数据,由于这个策略的逻辑,是不太可能同时出现多空持仓的,所以发现同时出现多空持仓就抛出错误
              Log(pos)
              throw \"同时有多空持仓\"                  // 抛出错误,让策略停止
          }
          // 根据状态而定
          if (pos.length == 0) {                    // 根据持仓状态做出不同操作,pos.length == 0是当没有持仓时
              // 未持仓了,统计一次收益
              if (!IsVirtual()) {
                  var currTotalEq = getTotalEquity()
                  if (currTotalEq) {
                      LogProfit(currTotalEq - totalEq, \"当前总权益:\", currTotalEq)
                  }
              }
    
              buyOrderId = openLong(ticker.Last - targetProfit, amount)       // 挂开多仓的买单
              sellOrderId = openShort(ticker.Last + targetProfit, amount)     // 挂开空仓的卖单
          } else if (pos[0].Type == PD_LONG) {   // 有多头持仓,挂单位置、数量有所不同
              var n = 1
              var price = ticker.Last
              buyOrderId = openLong(price - targetProfit * n, amount)
              sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
          } else if (pos[0].Type == PD_SHORT) {   // 有空头持仓,挂单位置、数量有所不同
              var n = 1
              var price = ticker.Last
              buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
              sellOrderId = openShort(price + targetProfit * n, amount)
          }
    
          if (!sellOrderId || !buyOrderId) {   // 如果有一边挂单失败就取消所有挂单,重来
              cancelAll()
              buyOrderId = null 
              sellOrderId = null
              continue
          } 
    
          while (1) {  // 挂单完成,开始监控订单
              var isFindBuyId = false 
              var isFindSellId = false
              var orders = _C(exchange.GetOrders)
              for (var i = 0 ; i < orders.length ; i++) {
                  if (buyOrderId == orders[i].Id) {
                      isFindBuyId = true 
                  }
                  if (sellOrderId == orders[i].Id) {
                      isFindSellId = true 
                  }               
              }
              if (!isFindSellId && !isFindBuyId) {    // 检测到买卖单都成交了
                  cancelAll()
                  break
              } else if (!isFindBuyId) {   // 检测到买单成交
                  Log(\"买单成交\")
                  cancelAll()
                  break
              } else if (!isFindSellId) {  // 检测到卖单成交
                  Log(\"卖单成交\")
                  cancelAll()
                  break
              }
              LogStatus(_D())
              Sleep(3000)
          }
          Sleep(500)
      }
    

整个逻辑和设计就讲解完了。

回测

让策略经历一次5月19日的行情。

1763ccc10fd4a299b2db1763ccc10fd4a299b2db

167521e5bd36ee139298167521e5bd36ee139298

可以看到,类马丁策略依然是有一定风险的。

实盘可以用OKEX V5模拟盘跑跑玩一下

161617cfc9bfd36a7143161617cfc9bfd36a7143

策略地址:https://www.fmz.com/strategy/294957

策略主要用于学习,真金白银慎用 ~!

FMZ量化交易平台邀请链接:https://www.fmz.com/

全球最大交易所币安,国区邀请链接:https://accounts.binance.com/zh-CN/register?ref=16003031  币安注册不了IP地址用香港,居住地选香港,认证照旧,邮箱推荐如gmail、outlook。支持币种多,交易安全!

买好币上KuCoin:https://www.kucoin.com/r/af/1f7w3  CoinMarketCap前五的交易所,注册友好操简单快捷!

目前不清退的交易所推荐:

1、全球第二大交易所OKX欧意,邀请链接:https://www.myts3cards.com/cn/join/1837888 注册简单,交易不需要实名,新用户能开合约,币种多,交易量大!。

2、老牌交易所比特儿现改名叫芝麻开门 :https://www.gate.win/signup/649183

买好币上币库:https://www.kucoin.com/r/1f7w3

火必所有用户现在可用了,但是要重新注册账号火币:https://www.huobi.com

全球最大交易所币安,

国区邀请链接:https://accounts.suitechsui.mobi/zh-CN/register?ref=16003031 支持86手机号码,网页直接注册。