avatar of 发明者量化-小小梦 发明者量化-小小梦
フォロー ダイレクトメッセージ
4
フォロー
1271
フォロワー

プログラム取引におけるKラインデータ処理に関する簡単な説明

作成日:: 2019-08-13 11:11:38, 更新日:: 2023-10-20 20:06:13
comments   8
hits   4628

プログラム取引におけるKラインデータ処理に関する簡単な説明

プログラム取引におけるKラインデータ処理に関する簡単な説明

Kラインデータを使用してプログラムによる取引戦略を作成する場合、通常、12分周期のKラインデータ、4時間周期のKラインデータなど、非標準の周期のKラインデータを使用する必要があることがよくあります。このような非標準的な期間は直接取得できません。では、このような要求に私たちはどう応えればよいのでしょうか? 答えは、間違いなく方法はあるということです。 非標準サイクルは、より小さなサイクルのデータを統合して合成することで得られます。複数のサイクルの最高価格は合成後の最高価格としてカウントされ、最低価格は合成後の最低価格としてカウントされることを想像してください。価格は変更されません。、合成Kラインの原材料データの最初の始値が使用され、終値は合成Kラインの原材料データの最後の終値に対応し、時間は時間です。始値、出来高は原材料データの取引量を合計して算出します。 写真の通り:

  • ### アイデア

ブロックチェーン資産市場 BTC_USDT を例に、1 時間を 4 時間に合成します。

プログラム取引におけるKラインデータ処理に関する簡単な説明

プログラム取引におけるKラインデータ処理に関する簡単な説明

プログラム取引におけるKラインデータ処理に関する簡単な説明

プログラム取引におけるKラインデータ処理に関する簡単な説明

|時間|高値|始値|安値|終値| |- |- |- |- |-| |2019.8.12 00:00|11447.07|11382.57|11367.2|11406.92| |2019.8.12 01:00|11420|11405.65|11366.6|11373.83| |2019.8.12 02:00|11419.24|11374.68|11365.51|11398.19| |2019.8.12 03:00|11407.88|11398.59|11369.7|11384.71|

これら4つの1時間サイクルのデータは4時間サイクルデータに統合されます。始値は最初の00:00の始値: 11382.57です。 終値は最後のもの、つまり03:00の終値:11384.71です。 最高価格はここの最高価格です: 11447.07 最低価格はここです: 11365.51 4時間サイクルの開始時間は00:00、1時間Kラインの開始時間は2019.8.12 00:00です。 取引量は1時間ごとに集計できます(主に、取引量データには表示されない価格の合成方法を観察するため)。ここでは詳細には触れません。

合成された 4 時間の K ラインは次のとおりです。 高値: 11447.07 オープン: 11382.57 安値: 11365.51 受信数: 11384.71 時間: 2019.8.12 00:00

プログラム取引におけるKラインデータ処理に関する簡単な説明

データが一貫していることがわかります。

  • ### 実装するためのコードを書く

予備的なアイデアを検証した後、この要件を予備的に実装するためのコードの作成を開始できます。

コードを直接リリースします。コードは参照用です。

    function GetNewCycleRecords (sourceRecords, targetCycle) {    // K线合成函数
        var ret = []

        // 首先获取源K线数据的周期
        if (!sourceRecords || sourceRecords.length < 2) {
            return null
        }
        var sourceLen = sourceRecords.length
        var sourceCycle = sourceRecords[sourceLen - 1].Time - sourceRecords[sourceLen - 2].Time

        if (targetCycle % sourceCycle != 0) {
            Log("targetCycle:", targetCycle)
            Log("sourceCycle:", sourceCycle)
            throw "targetCycle is not an integral multiple of sourceCycle."
        }

        if ((1000 * 60 * 60) % targetCycle != 0 && (1000 * 60 * 60 * 24) % targetCycle != 0) {
            Log("targetCycle:", targetCycle)
            Log("sourceCycle:", sourceCycle)
            Log((1000 * 60 * 60) % targetCycle, (1000 * 60 * 60 * 24) % targetCycle)
            throw "targetCycle cannot complete the cycle."
        }

        var multiple = targetCycle / sourceCycle


        var isBegin = false 
        var count = 0
        var high = 0 
        var low = 0 
        var open = 0
        var close = 0 
        var time = 0
        var vol = 0
        for (var i = 0 ; i < sourceLen ; i++) {
            // 获取 时区偏移数值
            var d = new Date()
            var n = d.getTimezoneOffset()

            if (((1000 * 60 * 60 * 24) - sourceRecords[i].Time % (1000 * 60 * 60 * 24) + (n * 1000 * 60)) % targetCycle == 0) {
                isBegin = true
            }

            if (isBegin) {
                if (count == 0) {
                    high = sourceRecords[i].High
                    low = sourceRecords[i].Low
                    open = sourceRecords[i].Open
                    close = sourceRecords[i].Close
                    time = sourceRecords[i].Time
                    vol = sourceRecords[i].Volume

                    count++
                } else if (count < multiple) {
                    high = Math.max(high, sourceRecords[i].High)
                    low = Math.min(low, sourceRecords[i].Low)
                    close = sourceRecords[i].Close
                    vol += sourceRecords[i].Volume

                    count++
                }

                if (count == multiple || i == sourceLen - 1) {
                    ret.push({
                        High : high,
                        Low : low,
                        Open : open,
                        Close : close,
                        Time : time,
                        Volume : vol,
                    })
                    count = 0
                }
            }
        }

        return ret 
    }

    // 测试
    function main () {
        while (true) {
            var r = exchange.GetRecords()                           // 原始数据,作为合成K线的基础K线数据,例如要合成4小时K线,可以用1小时K线作为原始数据。
            var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4)      // 通过 GetNewCycleRecords 函数 传入 原始K线数据 r , 和目标周期, 1000 * 60 * 60 * 4 即 目标合成的周期 是4小时K线数据。

            $.PlotRecords(r2, "r2")                                 // 策略类库栏 可以勾选画线类库,调用 $.PlotRecords 画线类库 导出函数 画图。
            Sleep(1000)                                             // 每次循环间隔 1000 毫秒,防止访问K线接口获取数据过于频繁,导致交易所限制。
        }
    }

実は、K ラインを合成するには、2 つのものが必要です。1 つ目は、生の材料データ、つまり、小周期の K ライン データです。var r = exchange.GetRecords() 得られた小周期K線データ。 2つ目は、Kラインデータ合成の対象期間である合成期間を明確に定義することです。 その後、GetNewCycleRecords 関数のアルゴリズムを通じて、合成された K ライン配列構造のデータが最終的に返されます。 以下の点に注意してください。

    1. ターゲット サイクルは、GetNewCycleRecords 関数にデータ原材料として渡す K ラインのサイクルよりも小さくすることはできません。 これは、小さなサイクルを使用して、より小さなサイクルからのデータを合成することが不可能であるためです。
    1. 設定する対象期間は、終了した期間である必要があります。 サイクルクローズとは何ですか? 簡単に言えば、1 時間または 1 日以内に、ターゲット サイクル時間の範囲が組み合わされて、閉じたループが形成されます。 例: 例えば、12分周期のKラインは毎時0:00(0:00を例にとる)に始まり、最初の周期は00:00:00 ~ 00:12:002番目のサイクルは00:12:00 ~ 00:24:003番目のサイクルは00:24:00 ~ 00:36:004番目のサイクルは00:36:00 ~ 00:48:00、第5サイクルは00:48:00 ~ 01:00:00 、合計1時間になります。

    13 分周期の場合はオープン サイクルであり、このようなサイクルで計算されるデータは、合成データの開始点によって合成データが異なるため、一意ではありません。

実際のディスクは次のように実行されました: プログラム取引におけるKラインデータ処理に関する簡単な説明

為替チャートを比較する プログラム取引におけるKラインデータ処理に関する簡単な説明

  • ## Kラインデータを使用して必要なデータ構造を構築する

グループのメンバーからよく質問があります: 各 K ラインの最高価格の移動平均を計算したいのですが、どうすればいいですか?

通常、移動平均線は終値の平均を計算して移動平均線を形成しますが、最高値、最安値、始値などを計算する必要がある場合もあります。 現時点では、exchange.GetRecords() 関数によって返される K ライン データは、インジケーター計算関数に直接渡されます。

例えば: talib.MA 移動平均インジケーター計算関数には 2 つのパラメーターがあります。最初のパラメーターは渡す必要のあるデータであり、2 番目のパラメーターはインジケーター期間パラメーターです。 例えば、次の指標を計算したいとします。 プログラム取引におけるKラインデータ処理に関する簡単な説明

Kラインサイクルは4時間です。 為替チャートでは、移動平均期間パラメータが 9 で移動平均が設定されています。 そして計算のデータソースは各バーの最高価格に設定されています。 プログラム取引におけるKラインデータ処理に関する簡単な説明 つまり、この移動平均は、インジケーターの移動平均を構成する 9 本の 4 時間 K ライン バーの最高価格の平均です。

自分でデータを構築し、それが取引所のチャートで計算されたものと同じかどうかを確認してみましょう。

  var highs = []
  for (var i = 0 ; i < r2.length ; i++) {
      highs.push(r2[i].High)
  }

移動平均インジケーターを導出するには、各バーの最高価格の平均を計算する必要があるためです。 次に、各データ要素が各バーの最高価格に対応する配列を最初に構築する必要があります。 highs 変数は最初は空の配列であり、次に r2 ローソク足データ変数を走査していることがわかります (r2 を覚えていませんか? 上記の 4 時間ローソク足を合成するメイン関数のコードを参照してください)。 r2の各バーの最高価格を読み取ります(つまりr2[i].High 、 i の範囲は 0 から r2.length - 1 ) で、それを highs にプッシュします。このようにして、K ライン データ バーと 1 対 1 に対応するデータ構造が構築されます。

この時点で、高値を talib.MA 関数に渡して移動平均を計算できます。

完全な例:

  function main () {
      while (true) {
          var r = exchange.GetRecords()
          var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4)
          if (!r2) {
              continue
          }

          $.PlotRecords(r2, "r2")                                               // 画出K线

          var highs = []
          for (var i = 0 ; i < r2.length ; i++) {
              highs.push(r2[i].High)
          }

          var ma = talib.MA(highs, 9)                                           // 用均线指标函数 talib.MA 计算 均线指标
          $.PlotLine("high_MA9", ma[ma.length - 2], r2[r2.length - 2].Time)     // 使用画线类库把均线指标画在图表上

          Sleep(1000)
      }
  }

バックテストの実行:

プログラム取引におけるKラインデータ処理に関する簡単な説明

図のマウス位置の移動平均指標の値は11466.9289

上記のコードを戦略にコピーしてテストを実行できます。「線画ライブラリ」をチェックして保存することを忘れないでください。

  • ## デジタル通貨市場でKラインデータを取得する方法

Inventor Quantitative Trading Platform には、K ライン データを取得できる exchange.GetRecords 関数というパッケージ化されたインターフェイスがすでにあります。 以下では、データを取得するために交換Kラインデータインターフェースに直接アクセスすることに焦点を当てています。これは、より多くのKラインを取得するためにパラメータを指定する必要があることがあるためです。カプセル化されたGetRecordsインターフェース 通常は100個が返されます。戦略が最初に 100 を超える K ラインを必要とする場合は、収集して待機する必要があります。 戦略をできるだけ速く実行するために、関数を自分でカプセル化し、取引所の K ライン インターフェイスに直接アクセスし、パラメータを指定してより多くの K ライン データを取得することができます。

Huobi の BTC_USDT 取引ペアを例にとると、この要件を実装します。

取引所の API ドキュメントを見つけて、K ライン インターフェースの説明を表示します。 プログラム取引におけるKラインデータ処理に関する簡単な説明

  https://api.huobi.pro/market/history/kline?period=1day&size=200&symbol=btcusdt

パラメータ: |パラメータ名|タイプ|必須|説明|値| |-|-|-|-|-| |シンボル|文字列|true|取引ペア|btcusdt、ethbtc…| |period|文字列|true|データの時間粒度、つまり各キャンドルの時間間隔を返します|1分、5分、15分、30分、60分、1日、1か月、1週間、1年| |size|integer|false|K ラインデータの数を返します|[1, 2000]|

テストコード:

  function GetRecords_Huobi (period, size, symbol) {
      var url = "https://api.huobi.pro/market/history/kline?" + "period=" + period + "&size=" + size + "&symbol=" + symbol
      var ret = HttpQuery(url)

      try {
          var jsonData = JSON.parse(ret)
          var records = []
          for (var i = jsonData.data.length - 1; i >= 0 ; i--) {
              records.push({
                  Time : jsonData.data[i].id * 1000,
                  High : jsonData.data[i].high,
                  Open : jsonData.data[i].open,
                  Low : jsonData.data[i].low,
                  Close : jsonData.data[i].close,
                  Volume : jsonData.data[i].vol,
              })
          }
          return records
      } catch (e) {
          Log(e)
      }
  }  


  function main() {
      var records = GetRecords_Huobi("1day", "300", "btcusdt")
      Log(records.length)
      $.PlotRecords(records, "K")
  }

Python バージョン、Huobi 取引所インターフェースへのアクセス例:

#!python3
import json
import urllib2

def GetRecords_Huobi(period, size, symbol):
    headers = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
    url = "https://api.huobi.pro/market/history/kline?" + "period=" + period + "&size=" + size + "&symbol=" + symbol
    request = urllib2.Request(url)  
    request.add_header('User-Agent','Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6')  
    opener = urllib2.build_opener()  
    f= opener.open(request)  
    ret = f.read().decode('utf-8')  
    
    try :
        jsonData = json.loads(ret)
        
        records = []
        for i in range(len(jsonData["data"]) - 1, -1, -1):
            records.append({
                "Time" : jsonData["data"][i]["id"] * 1000, 
                "High" : jsonData["data"][i]["high"], 
                "Open" : jsonData["data"][i]["open"], 
                "Low" : jsonData["data"][i]["low"], 
                "Close" : jsonData["data"][i]["close"], 
                "Volume" : jsonData["data"][i]["vol"], 
            })
        return records
    except Exception as e:
        Log(e)
        
def main():
    r = GetRecords_Huobi("1day", "300", "btcusdt")
    Log(len(r))
    ext.PlotRecords(r, "K")   # 需要引用Python画线类库


Python バージョン、Binance Exchange の K ライン インターフェースにアクセスする例:

#!python3
import json
import urllib2

def GetRecords_Huobi(period, size, symbol):
    headers = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
    url = "https://api.binance.com/api/v3/klines?symbol=" + symbol + "&interval=" + period
    request = urllib2.Request(url)  
    request.add_header('User-Agent','Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6')  
    opener = urllib2.build_opener()  
    f= opener.open(request)  
    ret = f.read().decode('utf-8')  
    try :
        jsonData = json.loads(ret)
        
        records = []
        for i in range(len(jsonData)):
            records.append({
                "Time" : float(jsonData[i][0]),
                "High" : float(jsonData[i][2]), 
                "Open" : float(jsonData[i][1]), 
                "Low" : float(jsonData[i][3]), 
                "Close" : float(jsonData[i][4]), 
                "Volume" : float(jsonData[i][5]), 
            })
        return records
    except Exception as e:
        Log(e)
        
def main():
    r = GetRecords_Huobi("1m", "300", "BTCUSDT")
    Log(len(r))
    ext.PlotRecords(r, "K")   # 需要引用Python画线类库


プログラム取引におけるKラインデータ処理に関する簡単な説明

プログラム取引におけるKラインデータ処理に関する簡単な説明

ログを見ると、records.length が 300 であることがわかります。これは、K ライン データのレコードが 300 バーあることを意味します。 プログラム取引におけるKラインデータ処理に関する簡単な説明