avatar of 发明者量化-小小梦 发明者量化-小小梦
집중하다 사신
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)

그리드 전략의 특징은 추세장에서는 큰 변동손실이 발생하고, 변동성이 큰 시장에서만 수익이 반등한다는 것입니다. 따라서 그리드 전략은 무위험이 아닙니다. 현물 전략은 여전히 ​​유지될 수 있지만, 선물 계약 그리드 전략은 더 위험하며 그리드 매개변수에 대한 보수적인 설정이 필요합니다.