
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:
Wir nehmen den Blockchain-Asset-Markt BTC_USDT als Beispiel und synthetisieren 1 Stunde in 4 Stunden.




|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

Sie sehen, dass die Daten konsistent sind.
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:
00: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:

Wechselkurstabellen vergleichen

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

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.
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:

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!
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:

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


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.
