avatar of 发明者量化-小小梦 发明者量化-小小梦
konzentrieren Sie sich auf Private Nachricht
4
konzentrieren Sie sich auf
1271
Anhänger

Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Erstellt in: 2019-08-13 11:11:38, aktualisiert am: 2023-10-20 20:06:13
comments   8
hits   4628

Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Beim Schreiben programmatischer Handelsstrategien unter Verwendung von K-Line-Daten besteht häufig die Notwendigkeit, einige nicht standardmäßige K-Line-Daten zu verwenden, wie z. B. 12-Minuten-Perioden-K-Line-Daten, 4-Stunden-Perioden-K-Line-Daten, normalerweise Diese Art von Nicht-Standard-Zeitraum kann nicht direkt abgerufen werden. Wie also reagieren wir auf solche Forderungen? Die Antwort ist definitiv: Es gibt einen Weg. Nicht-Standard-Zyklen können durch Zusammenführen und Synthetisieren von Daten aus kleineren Zyklen erhalten werden. Sie können sich vorstellen, dass der höchste Preis in mehreren Zyklen als der höchste Preis nach der Synthese gezählt wird und der niedrigste Preis als der niedrigste Preis nach der Synthese gezählt wird. Die Eröffnung Der Preis wird sich nicht ändern. Es wird der erste Eröffnungspreis der Rohstoffdaten der synthetisierten K-Linie verwendet, der Schlusspreis entspricht dem letzten Schlusspreis der Rohstoffdaten der synthetisierten K-Linie, die Zeit ist die Zeit des Eröffnungskurses und das Handelsvolumen wird durch Summierung der Transaktionsvolumina der Rohstoffdaten berechnet. Wie im Bild gezeigt:

  • ### Ideen

Wir nehmen den Blockchain-Asset-Markt BTC_USDT als Beispiel und synthetisieren 1 Stunde in 4 Stunden.

Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

|Zeit|Hoch|Eröffnung|Tief|Schluss| |- |- |- |- |-| |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|

Die Daten dieser vier 1-Stunden-Zyklen werden zu einem 4-Stunden-Zyklus zusammengefasst. Der Eröffnungskurs ist der Eröffnungskurs der ersten 00:00-Uhrzeit: 11382,57 Der Schlusskurs ist der letzte, also der Schlusskurs um 03:00 Uhr: 11384,71 Der höchste Preis ist hier der höchste Preis: 11447,07 Der niedrigste Preis ist hier: 11365.51 Die Startzeit des 4-Stunden-Zyklus ist 00:00 Uhr, die Startzeit der 1-Stunden-K-Linie ist 2019.8.12 00:00 Uhr Das Handelsvolumen kann stündlich summiert werden (hauptsächlich um zu beobachten, wie der Preis synthetisiert wird, was in den Handelsvolumendaten nicht angezeigt wird). Ich werde hier nicht ins Detail gehen.

Die synthetisierte 4-Stunden-K-Linie lautet: Hoch: 11447,07 Offen: 11382.57 Tiefststand: 11365,51 Empfangen: 11384,71 Zeit: 2019.8.12 00:00

Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Sie sehen, dass die Daten konsistent sind.

  • ### Schreiben Sie Code zur Implementierung

Nachdem Sie die vorläufigen Ideen überprüft haben, können Sie mit dem Schreiben von Code beginnen, um diese Anforderung vorläufig umzusetzen.

Geben Sie den Code direkt frei, der Code dient nur als Referenz:

    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线接口获取数据过于频繁,导致交易所限制。
        }
    }

Um die K-Linie zu synthetisieren, sind tatsächlich zwei Dinge erforderlich: Das erste sind Rohmaterialdaten, d. h. K-Liniendaten eines kleinen Zeitraums.var r = exchange.GetRecords() Die erhaltenen K-Linien-Daten mit kleiner Periode. Zweitens muss der Synthesezeitraum klar definiert werden, d. h. der Zielzeitraum für die K-Line-Datensynthese. Anschließend können über den Algorithmus der Funktion GetNewCycleRecords schließlich die Daten einer synthetisierten K-Line-Array-Struktur zurückgegeben werden. Es ist zu beachten, dass:

    1. Der Zielzyklus kann nicht kleiner sein als der Zyklus der K-Linie, die Sie als Datenrohmaterial an die Funktion GetNewCycleRecords übergeben. Dies liegt daran, dass es unmöglich ist, einen kleinen Zyklus zu verwenden, um Daten aus einem kleineren Zyklus zu synthetisieren.
    1. Der festgelegte Zielzeitraum muss ein abgeschlossener Zeitraum sein. Was ist Zyklusschließung? Vereinfacht ausgedrückt werden die Zielzykluszeitbereiche innerhalb einer Stunde oder eines Tages zu einem geschlossenen Kreislauf zusammengefügt. Beispiel: Beispielsweise beginnt die K-Linie eines 12-Minuten-Zyklus um 0:00 Uhr jeder Stunde (nehmen wir 0:00 als Beispiel), und der erste Zyklus ist00:00:00 ~ 00:12:00, der zweite Zyklus ist00:12:00 ~ 00:24:00, der dritte Zyklus ist00:24:00 ~ 00:36:00, der vierte Zyklus ist00:36:00 ~ 00:48:00, der fünfte Zyklus ist00:48:00 ~ 01:00:00 , was eine volle Stunde ausmacht.

    Handelt es sich um einen 13-Minuten-Zyklus, handelt es sich um einen offenen Zyklus, und die in einem solchen Zyklus berechneten Daten sind nicht eindeutig, da die synthetisierten Daten je nach Startpunkt der synthetisierten Daten unterschiedlich sind.

Die eigentliche Diskette wurde ausgeführt: Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Wechselkurstabellen vergleichen Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

  • ## Verwenden Sie K-Line-Daten, um die erforderliche Datenstruktur zu erstellen

Gruppenmitglieder stellen häufig Fragen: Ich möchte den gleitenden Durchschnitt des höchsten Preises jeder K-Linie berechnen. Was soll ich tun?

Normalerweise berechnen wir den gleitenden Durchschnitt, indem wir den Durchschnitt der Schlusskurse berechnen, um den gleitenden Durchschnitt zu bilden, aber manchmal besteht die Notwendigkeit, den höchsten Kurs, den niedrigsten Kurs, den Eröffnungskurs usw. zu berechnen. Zu diesem Zeitpunkt kann man nicht einfachexchange.GetRecords() Die von der Funktion zurückgegebenen K-Linien-Daten werden direkt an die Indikatorberechnungsfunktion übergeben.

Zum Beispiel: Die Berechnungsfunktion des gleitenden Durchschnittsindikators talib.MA hat zwei Parameter. Der erste Parameter sind die Daten, die übergeben werden müssen, und der zweite Parameter ist der Indikatorperiodenparameter. Wir wollen beispielsweise folgende Kennzahlen berechnen Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Der K-Linien-Zyklus beträgt 4 Stunden. Auf dem Börsendiagramm wurde ein gleitender Durchschnitt mit einem gleitenden Durchschnittsperiodenparameter von 9 festgelegt. Und die Datenquelle für die Berechnung wird auf den höchsten Preis jedes Balkens eingestellt. Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel Das heißt, dieser gleitende Durchschnitt ist der Durchschnitt der höchsten Preise von 9 4-Stunden-K-Linien-Balken, die den gleitenden Durchschnitt des Indikators bilden.

Lassen Sie uns selbst einige Daten erstellen und prüfen, ob sie mit den im Diagramm der Börse berechneten Daten übereinstimmen.

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

Da wir den Durchschnitt der höchsten Preise jedes Balkens berechnen müssen, um den gleitenden Durchschnittsindikator abzuleiten. Dann müssen Sie zunächst ein Array erstellen, in dem jedes Datenelement dem höchsten Preis jedes Balkens entspricht. Sie können sehen, dass die Variable „highs“ zunächst ein leeres Array ist, und dann durchlaufen wir die Datenvariable „r2“ des Candlesticks (Sie erinnern sich nicht an r2? Sehen Sie sich den Code in der Hauptfunktion zur Synthese des 4-Stunden-Candlesticks oben an). Lesen Sie den höchsten Preis jedes Balkens von r2 (d. h. r2[i].High, i reicht von 0 bis r2.length - 1) und schiebt es dann in den Hochwert. Auf diese Weise wird eine Datenstruktur erstellt, die eins zu eins mit den K-Line-Datenbalken übereinstimmt.

An diesem Punkt können Höchstwerte an die Funktion talib.MA übergeben werden, um den gleitenden Durchschnitt zu berechnen.

Vollständiges Beispiel:

  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)
      }
  }

Backtest-Lauf:

Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Sie können sehen, dass die gleitenden Durchschnittswerte des Indikators an der Mausposition in der Abbildung sind11466.9289

Der obige Code kann in die Strategie kopiert werden, um den Test auszuführen. Denken Sie daran, „Line Drawing Library“ zu aktivieren und zu speichern!

  • ## So erhalten Sie K-Line-Daten auf dem digitalen Währungsmarkt

Die Inventor Quantitative Trading Platform verfügt bereits über eine gepackte Schnittstelle, nämlich die Funktion exchange.GetRecords, mit der K-Line-Daten abgerufen werden können. Im Folgenden wird der direkte Zugriff auf die K-Line-Datenschnittstelle zum Abrufen von Daten erläutert. Manchmal müssen Sie Parameter angeben, um weitere K-Lines abzurufen. Die Schnittstelle GetRecords ist gekapselt Normalerweise werden 100 zurückgegeben. Wenn die Strategie zunächst mehr als 100 K-Linien erfordert, heißt es sammeln und warten. Um die Strategie so schnell wie möglich auszuführen, können Sie selbst eine Funktion kapseln, direkt auf die K-Line-Schnittstelle der Börse zugreifen und Parameter angeben, um weitere K-Line-Daten zu erhalten.

Am Beispiel des BTC_USDT-Handelspaars von Huobi implementieren wir diese Anforderung:

Suchen Sie nach der API-Dokumentation der Börse und sehen Sie sich die Beschreibung der K-Line-Schnittstelle an: Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

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

Parameter: |Parametername|Typ|Erforderlich|Beschreibung|Wert| |-|-|-|-|-| |Symbol|Zeichenfolge|true|Handelspaar|btcusdt, ethbtc…| |period|string|true|Gibt die zeitliche Datengranularität zurück, d. h. das Zeitintervall jeder Kerze|1 Min., 5 Min., 15 Min., 30 Min., 60 Min., 1 Tag, 1 Mon., 1 Woche, 1 Jahr| |Größe|Ganzzahl|Falsch|Gibt die Anzahl der K-Line-Daten zurück|[1, 2000]|

Testcode:

  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-Version, Beispiel für den Zugriff auf die Huobi-Austauschschnittstelle:

#!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-Version, ein Beispiel für den Zugriff auf die K-Line-Schnittstelle von Binance Exchange:

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


Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel

Wir können im Protokoll sehen, dass die Datensatzlänge 300 beträgt, was bedeutet, dass 300 Balken mit Datensätzen der K-Linien-Daten vorhanden sind. Eine kurze Diskussion über die K-Line-Datenverarbeitung im programmierten Handel