プログラム化取引におけるK線データ処理の浅谈

作者: リン・ハーン小さな夢, 作成日:2019-08-13 11:11:38, 更新日:2023-10-20 20:06:13

img

プログラム化取引におけるK線データ処理の浅谈

プログラム化取引戦略を書き出すとき,K線データを使用するときに,通常,直接入手できない12分周期K線データ,4時間周期K線データなどの非標準周期K線データを使用する必要がしばしばあります. 答えは,きっとあるだろう. 非標準サイクルは,より小さなサイクルのデータによって,組み合わせた合成を取得することができます. 想像してみてください,複数のサイクルの最高価格,合成後の最高価格,最小価格,合成後の最低価格として計算され,開場価格は変わらない. 合成されたKラインの原料データの最初の開場価格,閉場価格は,合成されたKラインの原料データの最後の閉場価格に対応します. 時間は開場価格の時間であり,取引量は原料データの取引量を計算して求められます. メディアの報道によると

  • 考える

    ブロックチェーンの資産市場BTC_USDTを例に挙げると,1時間から4時間になります.

    img

    img

    img

    img

    時間 高さ オープン 収束
    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時間周期のデータは,1つの4時間周期のデータを組み合わせて,最初の 00:00 の開通価格:11382.57 となります. 閉じる価格は最後の1です. 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

    img

    データは一致しているのがわかります.

  • コード作成の実装

    初期アイデアを検証した後に,手書きのコードで初期実現を図ることができます.

    直接コードを出して,コードは参考学習のみです:

      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線データです.var r = exchange.GetRecords()2つ目は,K線データの合成の目標周期である,どのサイクルの大きなサイクルが合体されるかを明確にする必要があります. このとき,GetNewCycleRecordsのアルゴリズムを使用して,最終的にK線配列構造のデータを返します. メディアの報道によると,

    • 1, 目標周期は,GetNewCycleRecords関数にデータ原料として渡すK行の周期より小さいものであってはならない. 短い周期でより小さな周期のデータを合成することはできません.

    • 2, 設定された目標周期は,周期閉である必要があります. サイクルの閉ざしとは何か? 簡単に言うと,目標周期の時間帯が1時間または1日間で結合して,閉ざされた循環を形成する. 例えば: 例えば,12分周期のK線は,毎時間の0分0秒から始まる (例えば0時),最初の周期は00:00:00 ~ 00:12:00この2つの周期は,00:12:00 ~ 00:24:00この3つの周期は,00:24:00 ~ 00:36:00この4つの周期は,00:36:00 ~ 00:48:00この5つの周期は,00:48:00 ~ 01:00:00半時間ほどで終わります.

      13分サイクルの場合,閉まっていないサイクルの場合,このようなサイクルの計算されたデータはユニークではありません. 合成されたデータの開始地点によって異なるため,合成されたデータは異なります.

    リアルディスクが起動した:img

    比較取引所グラフimg

  • K線データで構築されるデータ構造

    "K線ごとに最高値の平均線を計算したい"とよく聞かれます.

    通常,平均線は計算された閉店価格の平均値で,平均線を構成しますが,時には最高価格,最低価格,開店価格などを計算する必要もあります. この時点で,exchange.GetRecords()函数が返したK線データは指数計算関数に直接伝達される.

    例えば:talib.MA均線指標計算関数には,最初のパラメータが入力されるデータであり,第2パラメータは指標周期パラメータである. この図で示したように,img

    K線周期は4時間. 取引所のチャートでは,平均線が設定されており,平均線周期パラメータは9である. 計算したデータソースは,バーごとに最高価格を設定します.imgつまり,この均線は9つの4時間周期のK線Barの最高価格の平均を計算した平均値であり,構成する指標均線である.

    取引所のグラフで計算されているように,データ計算を自分で作ってみましょう.

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

    平均線指標は,各バーの最高価格を計算する平均値である. この場合,各データ要素が各バーの最高値に対応する配列を構成する必要があります. highs 変数は最初は空の配列で,次に r2 の K 線データ変数 (r2 を覚えてないか? 4 時間 K 線を合成したメイン関数でコードを見てください) を走ります. r2 の各Bar の最大値 (すなわち r2[i].High, i は 0 から r2.length - 1 までの範囲を値とする) を読み,highs にプッシュします.

    このとき,highsは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)
        }
    }
    

    復習が実行される:

    img

    平均線は,マウスの停留位置の値です.11466.9289

    上のコードは,ポリシーにコピーしてテストを実行できます. "Draw Line Library"をクリックして保存してください.

  • デジタル通貨市場のK線データ取得方法

    発明者による量化取引プラットフォームには,K線データを入手するための,既にパッケージ化されたインターフェースである exchange.GetRecords機能があります. 以下は,直接アクセスした取引所のK線データインターフェイスからデータを取得することを重んじる.時には,パラメータを指定してより多くのK線を取得する必要があるため,GetRecordsインターフェースをパッケージ化した. 一般的には100根を返します. 策略が初期に100根以上を必要とする場合,待機収集が必要です. 戦略をできるだけ早く実行するために,関数を自己包装して,直接取引所のK線インターフェースにアクセスし,パラメータを指定してより多くのK線データを取得することができます.

    この需要は BTC_USDTの取引ペアの例で実現しました.

    取引所のAPIドキュメントを検索し,K線インターフェースの説明を参照してください:img

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

    パラメータ:

    パラメータ名 タイプ 必要なのか 記述 値引き
    シンボル 文字列 本当 取引は Btcusdt,ethbtc... ほら ほら
    期間 文字列 本当 データの時間粒子を返します. つまり,各列の時間間隔です. 1分,5分,15分,30分60分,1日,1ヶ月,1週間,1年
    サイズ 整数 偽り 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版,トークン取引所のインターフェースへのアクセス例:

#!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の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画线类库


img

img

ログに表示されるように, records.length を 300 でプリントします.img


関連性

もっと

バムマン3時間か6時間でkを合成できない.

バムマンif (((1000 * 60 * 60 * 24) - sourceRecords[i].Time % (1000 * 60 * 60 * 24) + (n * 1000 * 60)) % targetCycle == 0) { isBegin = true は,このリストのいずれかです {cH00ffff} この文には問題があります. 3時間か6時間でkを合成できない. 1時間,2時間,4時間のk線でkを合成できるだけです.

xis2004クラップする場合は,すべての歴史データをクラップすることができますか?

ワイルズチャンありがとうございました.

ワイルズチャン取引所は一度に300bitsをサポートしているようです. ありがとうございました.

小さな夢素晴らしい,時間を取って変更します.

小さな夢これは,取引所のインターフェースデータにアクセスするデータです. 取引所はあなたにどれだけのデータを与えるかです. つまり,一般的には最近の数百バーです.

小さな夢交換インターフェイスがサポートする最大返回数を上回る場合は,十分なK線データだけ収集できます.