4
Подписаться
1271
Подписчики

Новички в количественной торговле в криптовалютных кругах, пожалуйста, ознакомьтесь с этим - Приближаемся к количественной торговле в криптовалютных кругах (V)

Создано: 2021-05-28 09:50:12, Обновлено: 2023-09-21 21:06:08
comments   14
hits   2531

Новички в количественной торговле в криптовалютных кругах, пожалуйста, ознакомьтесь с этим - Приближаемся к количественной торговле в криптовалютных кругах (V)

Новички в количественной торговле в криптовалютных кругах, пожалуйста, ознакомьтесь с этим - Приближаемся к количественной торговле в криптовалютных кругах (V)

В предыдущей статье мы объяснили анализ торговой логики простой стратегии сетки. В этой статье мы продолжим завершать разработку этой обучающей стратегии.

  • Анализ логики транзакций В предыдущей статье мы упоминали, что транзакционное действие может быть инициировано, пока мы пересекаем каждую линию сетки и определяем, пересекает ли текущая цена линию сетки выше или ниже. Но на самом деле, есть еще много логических деталей. Новички, которые не понимают написание стратегии, часто формируют неправильное восприятие, что «логика очень проста, и код должен быть всего в несколько строк, но в реальном написании все еще есть много подробностей».

Первая деталь, которую нам необходимо рассмотреть, — это конструкция бесконечной сетки. Помните, в прошлой статье мы разработали функцию для генерации начальной структуры данных сетки?createNetЧто? Эта функция генерирует сеточную структуру данных с конечным числом линий сетки. А что, если цена выйдет за границы этой структуры данных сетки (за верхнюю линию сетки с самой высокой ценой и за нижнюю линию сетки с самой низкой ценой) во время работы стратегии? Поэтому нам сначала нужно добавить механизм расширения в структуру данных сетки.

Начните писать основную функцию стратегии, которая представляет собой код, запускающий выполнение стратегии.

  var diff = 50                                 // 全局变量,网格间距,可以设计成参数,方便讲解,我们把这个参数写死在代码里。
  function main() {
      // 实盘开始运行后,从这里开始执行策略代码
      var ticker = _C(exchange.GetTicker)       // 获取市场最新的行情数据ticker,ticker这个数据的结构参看FMZ API文档:https://www.fmz.com/api#ticker
      var net = createNet(ticker.Last, diff)    // 我们上篇设计的初始构造网格数据结构的函数,这里构造一个网格数据结构net

      while (true) {                            // 然后程序逻辑就进入了这个while死循环,策略执行到此将不停的循环执行这里{}符号之内的代码
          ticker = _C(exchange.GetTicker)       // 死循环代码部分的第一行,获取最新的行情数据,更新给ticker变量
          // 检查网格范围
          while (ticker.Last >= net[net.length - 1].price) {
              net.push({
                  buy : false,
                  sell : false,
                  price : net[net.length - 1].price + diff,
              })
          }
          while (ticker.Last <= net[0].price) {
              var price = net[0].price - diff
              if (price <= 0) {
                  break
              }
              net.unshift({
                  buy : false,
                  sell : false,
                  price : price,
              })
          }

          // 还有其它代码...
      }
  }

Код, который делает структуру данных сетки расширяемой, выглядит следующим образом (выдержка из приведенного выше кода):

        // 检查网格范围
        while (ticker.Last >= net[net.length - 1].price) {   // 如果价格超过网格最高价格的网格线
            net.push({                                       // 就在网格最高价格的网格线之后加入一个新的网格线
                buy : false,                                 // 初始化卖出标记
                sell : false,                                // 初始化买入标记
                price : net[net.length - 1].price + diff,    // 在之前最高价格的基础上再加一个网格间距
            })
        }
        while (ticker.Last <= net[0].price) {                // 如果价格低于网格最低价格的网格线
            var price = net[0].price - diff                  // 区别于向上添加,要注意向下添加新网格线的价格不能小于等于0,所以这里要判断
            if (price <= 0) {                                // 小于等于0就不添加了,跳出这层循环
                break
            }
            net.unshift({                                    // 就在网格最低价格的网格线之前添加一个新的网格线
                buy : false,
                sell : false,
                price : price,
            })
        }

Следующим шагом будет детальное рассмотрение того, как реализовать запуск транзакций.

  var diff = 50
  var amount = 0.002       // 增加一个全局变量,也可以设计成参数,当然为了简便讲解,我们也写死在策略代码,
                           // 这个参数控制每次网格线上触发交易时的交易量
  function main() {
      var ticker = _C(exchange.GetTicker)
      var net = createNet(ticker.Last, diff)
      var preTicker = ticker       // 在主循环(死循环)开始前,设置一个变量,记录上一次的行情数据
      while (true) {
          ticker = _C(exchange.GetTicker)
          // 检查网格范围
          while (ticker.Last >= net[net.length - 1].price) {
              net.push({
                  buy : false,
                  sell : false,
                  price : net[net.length - 1].price + diff,
              })
          }
          while (ticker.Last <= net[0].price) {
              var price = net[0].price - diff
              if (price <= 0) {
                  break
              }
              net.unshift({
                  buy : false,
                  sell : false,
                  price : price,
              })
          }  

          // 检索网格
          for (var i = 0 ; i < net.length ; i++) {     // 遍历网格数据结构中的所有网格线
              var p = net[i]
              if (preTicker.Last < p.price && ticker.Last > p.price) {         // 上穿,卖出,当前节点已经交易过不论SELL BUY ,都不再交易
                  if (i != 0) {
                      var downP = net[i - 1]
                      if (downP.buy) {
                          exchange.Sell(-1, amount, ticker)
                          downP.buy = false 
                          p.sell = false 
                          continue
                      }
                  }
                  if (!p.sell && !p.buy) {
                      exchange.Sell(-1, amount, ticker)
                      p.sell = true
                  }
              } else if (preTicker.Last > p.price && ticker.Last < p.price) {  // 下穿,买入
                  if (i != net.length - 1) {
                      var upP = net[i + 1]
                      if (upP.sell) {
                          exchange.Buy(-1, amount * ticker.Last, ticker)
                          upP.sell = false 
                          p.buy = false 
                          continue
                      }
                  }
                  if (!p.buy && !p.sell) {
                      exchange.Buy(-1, amount * ticker.Last, ticker)
                      p.buy = true 
                  } 
              }
          }
          preTicker = ticker    // 把当前的行情数据记录在preTicker中,在下一次循环中,作为“上一次”行情数据和最新的对比,判断上穿下穿
          Sleep(500)
      }
  }  

Вы можете увидеть:

  • Условие пересечения линии сетки:preTicker.Last < p.price && ticker.Last > p.price
  • Условие пересечения линии сетки:preTicker.Last > p.price && ticker.Last < p.price

Вот о чем мы говорили в предыдущей статье:

Новички в количественной торговле в криптовалютных кругах, пожалуйста, ознакомьтесь с этим - Приближаемся к количественной торговле в криптовалютных кругах (V)

Пересечение вверх или вниз — это только первый шаг в определении возможности размещения сделки, который также требует определения отметок в данных линий сетки.

Если это восходящее пересечение, цена считается ниже текущей линии сетки и отметки покупки на ближайшей линии сетки. Если значение отметки покупки истинно, это означает, что предыдущая линия сетки была куплена, и предыдущая линия сетки сбрасывается. Маркировка покупки корня становится ложной, а текущая линия сетки сбрасывается на ложную.

После оценки предыдущего условия, если оно не сработало, продолжайте оценивать. Если обе отметки покупки/продажи на текущей линии сетки ложны, это означает, что текущая линия сетки может быть использована для торговли. Поскольку это восходящее пересечение, мы выполнить операцию продажи здесь. После выполнения отметьте флаг продажи текущей линии сетки как истинный.

Логика управления подземными переходами та же самая (оставим это на усмотрение новичков).

Полное бэктестирование стратегии

Для того, чтобы увидеть некоторые данные бэктестинга, написана функцияshowTblОтобразите данные.

function showTbl(arr) {
    var tbl = {
        type : "table", 
        title : "网格",
        cols : ["网格信息"],
        rows : []
    }
    var arrReverse = arr.slice(0).reverse()
    _.each(arrReverse, function(ele) {
        var color = ""
        if (ele.buy) {
            color = "#FF0000"
        } else if (ele.sell) {
            color = "#00FF00"
        }
        tbl.rows.push([JSON.stringify(ele) + color])
    })
    LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n 账户信息:", exchange.GetAccount())
}

Полный код стратегии:

/*backtest
start: 2021-04-01 22:00:00
end: 2021-05-22 00:00:00
period: 1d
basePeriod: 1m
exchanges: [{"eid":"OKEX","currency":"ETH_USDT","balance":100000}]
*/

var diff = 50
var amount = 0.002
function createNet(begin, diff) {
    var oneSideNums = 10
    var up = []
    var down = []
    for (var i = 0 ; i < oneSideNums ; i++) {
        var upObj = {
            buy : false,
            sell : false, 
            price : begin + diff / 2 + i * diff,
        }
        up.push(upObj)

        var j = (oneSideNums - 1) - i
        var downObj = {
            buy : false,
            sell : false,
            price : begin - diff / 2 - j * diff,
        }
        if (downObj.price <= 0) {  // 价格不能小于等于0 
            continue
        }
        down.push(downObj)
    }

    return down.concat(up)
}

function showTbl(arr) {
    var tbl = {
        type : "table", 
        title : "网格",
        cols : ["网格信息"],
        rows : []
    }
    var arrReverse = arr.slice(0).reverse()
    _.each(arrReverse, function(ele) {
        var color = ""
        if (ele.buy) {
            color = "#FF0000"
        } else if (ele.sell) {
            color = "#00FF00"
        }
        tbl.rows.push([JSON.stringify(ele) + color])
    })
    LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n 账户信息:", exchange.GetAccount())
}

function main() {
    var ticker = _C(exchange.GetTicker)
    var net = createNet(ticker.Last, diff)
    var preTicker = ticker 
    while (true) {
        ticker = _C(exchange.GetTicker)
        // 检查网格范围
        while (ticker.Last >= net[net.length - 1].price) {
            net.push({
                buy : false,
                sell : false,
                price : net[net.length - 1].price + diff,
            })
        }
        while (ticker.Last <= net[0].price) {
            var price = net[0].price - diff
            if (price <= 0) {
                break
            }
            net.unshift({
                buy : false,
                sell : false,
                price : price,
            })
        }

        // 检索网格
        for (var i = 0 ; i < net.length ; i++) {
            var p = net[i]
            if (preTicker.Last < p.price && ticker.Last > p.price) {         // 上穿,卖出,当前节点已经交易过不论SELL BUY ,都不再交易
                if (i != 0) {
                    var downP = net[i - 1]
                    if (downP.buy) {
                        exchange.Sell(-1, amount, ticker)
                        downP.buy = false 
                        p.sell = false 
                        continue
                    }
                }
                if (!p.sell && !p.buy) {
                    exchange.Sell(-1, amount, ticker)
                    p.sell = true
                }
            } else if (preTicker.Last > p.price && ticker.Last < p.price) {  // 下穿,买入
                if (i != net.length - 1) {
                    var upP = net[i + 1]
                    if (upP.sell) {
                        exchange.Buy(-1, amount * ticker.Last, ticker)
                        upP.sell = false 
                        p.buy = false 
                        continue
                    }
                }
                if (!p.buy && !p.sell) {
                    exchange.Buy(-1, amount * ticker.Last, ticker)
                    p.buy = true 
                } 
            }
        }

        showTbl(net)
        preTicker = ticker 
        Sleep(500)
    }
}

Тестирование стратегии:

Новички в количественной торговле в криптовалютных кругах, пожалуйста, ознакомьтесь с этим - Приближаемся к количественной торговле в криптовалютных кругах (V)

Новички в количественной торговле в криптовалютных кругах, пожалуйста, ознакомьтесь с этим - Приближаемся к количественной торговле в криптовалютных кругах (V)

Новички в количественной торговле в криптовалютных кругах, пожалуйста, ознакомьтесь с этим - Приближаемся к количественной торговле в криптовалютных кругах (V)

Можно заметить, что характеристики стратегии сетки таковы, что при наличии трендового рынка будут возникать большие плавающие убытки, а доходность будет расти только на волатильном рынке. Поэтому стратегия сетки не является безрисковой. Спотовая стратегия все еще может быть устойчивой, но стратегия сетки фьючерсных контрактов более рискованна и требует консервативных настроек параметров сетки.