Lors de l'écriture d'une stratégie de trading quantitative, en utilisant les données K-line, il y a souvent des cas où des données K-line de cycle non standard sont requises. par exemple, des données K-line de cycle de 12 minutes et des données de cycle de K-line de 4 heures sont requises. Habituellement, ces cycles non standard ne sont pas directement disponibles. Alors, comment gérer de tels besoins?
Les données de la ligne K du cycle non standard peuvent être obtenues en combinant les données du cycle plus petit. Imaginez ceci, le prix le plus élevé dans plusieurs cycles est compté comme le prix le plus élevé après la synthèse de la ligne K du cycle multiple, et le prix le plus bas est calculé comme le prix le plus bas après la synthèse, et le prix d'ouverture ne change pas. Le premier prix d'ouverture des données de matières premières de la ligne K est synthétisé. Le prix de clôture correspond au prix de clôture des dernières données de matières premières de la ligne K. Le temps utilise le temps de la ligne de prix d'ouverture k. Le volume de transaction utilise les données de matières premières qui ont été additionnées et calculées.
Comme indiqué sur la figure:
Prenons l'actif blockchain BTC_USDT comme exemple et synthétisons 1 heure en 4 heures.
Le temps | Le plus élevé | Il est ouvert. | Le plus bas | Je suis proche. |
---|---|---|---|---|
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 |
Les données de quatre cycles d'une heure sont combinées en une seule donnée de cycle de quatre heures.
Le prix d' ouverture est le prix d' ouverture de la première ligne K à 00h00 heure: 11382,57 Le prix de clôture est le prix de clôture de la dernière ligne k à 03:00: 11384.71 Le prix le plus élevé est de trouver le prix le plus élevé parmi eux: 11447,07 Le prix le plus bas est de trouver le prix le plus bas parmi eux: 11365,51
Note: le marché des contrats à terme sur matières premières chinois est fermé à 15 h par jour de négociation normal.
L'heure de début du cycle de 4 heures est l'heure de début de la première ligne K d'une heure, c'est-à-dire 2019.8.12 00:00
La somme du volume de toutes les lignes k de 1 heure est utilisée comme ce volume de lignes k de 4 heures.
Une ligne K de 4 heures est synthétisée:
High: 11447.07
Open: 11382.57
Low: 11365.51
Close: 11384.71
Time: 209.8.12 00:00
Vous pouvez voir que les données sont cohérentes.
Après avoir compris les idées initiales, vous pouvez écrire manuellement le code pour réaliser les exigences.
Ces codes sont uniquement à titre de référence:
function GetNewCycleRecords (sourceRecords, targetCycle) { // K line synthesis function
var ret = []
// First get the source K line data cycle
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++) {
// Get the time zone offset value
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
}
// test
function main () {
while (true) {
var r = exchange.GetRecords() // Raw data, as the basic K-line data of the synthesize K line. for example, to synthesize a 4-hour K-line, you can use the 1-hour K-line as the raw data.
var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4) // Pass the original K-line data r through the GetNewCycleRecords function, and the target cycles, 1000 * 60 * 60 * 4, ie the target synthesis cycle is 4 hours K-line data .
$.PlotRecords(r2, "r2") // The strategy class library bar can be selected by check the line class library, and calling the $.PlotRecords line drawing class library to export the function drawing.
Sleep(1000) // Each cycle is separated by 1000 milliseconds, preventing access to the K-line interface too much, resulting in transaction restrictions.
}
}
En fait, pour synthétiser la ligne K, vous avez besoin de deux choses. La première est les données de matières premières, c'est-à-dire les données de la ligne K d'un cycle plus petit.var r = exchange.GetRecords()
pour obtenir les données de la ligne K du cycle plus petit.
La seconde est de déterminer la taille du cycle de synthèse, nous utilisons l'algorithme de fonction GetNewCycleRecords pour le faire, puis vous pouvez finalement retourner les données d'une structure de matrice de ligne K synthétisée.
Veuillez noter:
Le cycle cible ne peut pas être inférieur au cycle de la ligne K que vous avez passé dans la fonction GetNewCycleRecords comme matière première pour les données.
Le cycle cible doit être réglé sur
par exemple:
La ligne K du cycle de 12 minutes commence à partir de 0h00 toutes les heures, le premier cycle est de 00h00 à 00h12 et le deuxième cycle est de 00h12 à 00h24 et le troisième cycle est de 00h24 à 00h36 et le quatrième cycle est de 00h36 à 00h48 et le cinquième cycle est de 00h48 à 00h00 à 00h00 ce qui correspond exactement à une heure complète.
si c'est un cycle de 13 minutes, il s'agira d'un cycle non fermé. Les données calculées par un tel cycle ne sont pas uniques car les données synthétisées diffèrent selon le point de départ des données synthétisées.
Faites-le sur le marché réel:
Graphique des échanges de contraste
Je veux calculer la moyenne mobile du prix le plus élevé pour toutes les lignes K. Que dois-je faire?
Habituellement, nous calculons les moyennes mobiles en utilisant la moyenne des prix de clôture, mais parfois il y a une demande pour utiliser le prix le plus élevé, le prix le plus bas, le prix d'ouverture et ainsi de suite.
pour ces demandes supplémentaires, les données de ligne K renvoyées par la fonction exchange.GetRecords (()) ne peuvent pas être transmises directement à la fonction de calcul de l'indicateur.
Par exemple:
Letalib.MA
La fonction de calcul de l'indicateur de moyenne mobile comporte deux paramètres, le premier étant les données à transmettre et le second le paramètre du cycle de l'indicateur.
Par exemple, nous devons calculer les indicateurs comme indiqué ci-dessous.
Le cycle de la ligne K est de 4 heures.
Sur le graphique des cotations boursières, une ligne moyenne a été fixée avec le paramètre de cycle de 9.
La source de données calculée utilise le prix le plus élevé par bar.
C'est-à-dire que cette ligne moyenne mobile est constituée de la moyenne du prix moyen le plus élevé de neuf barres de K-line de cycle de 4 heures.
Construisons nous-mêmes des données pour voir si c'est la même chose avec les données de l'échange.
var highs = []
for (var i = 0 ; i < r2.length ; i++) {
highs.push(r2[i].High)
}
Puisque nous devons calculer le prix le plus élevé de chaque barre pour obtenir la valeur de l'indicateur de moyenne mobile, nous devons construire un tableau dans lequel chaque élément de données a le prix le plus élevé pour chaque barre.
Vous pouvez voir que lehighs
la variable est initialement un tableau vide, puis nous traversons la variable de données de ligne r2 k (ne vous souvenez pas de la r2? Regardez le code dans la fonction principale qui synthétise la ligne K de 4 heures ci-dessus).
Lisez le prix le plus élevé de chaque barre de r2 (c'est-à-dire r2 [i].High, i varie de 0 à r2.longueur - 1), puis appuyez surhighs
De cette façon, nous construisons simplement une structure de données qui correspond un à un avec la barre de données de la ligne K.
En ce moment,highs
peut passer letalib.MA
fonction de calcul de la moyenne mobile.
Exemple complet:
function main () {
while (true) {
var r = exchange.GetRecords()
var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4)
if (!r2) {
Continue
}
$.PlotRecords(r2, "r2") // Draw the K line
var highs = []
for (var i = 0 ; i < r2.length ; i++) {
Highs.push(r2[i].High)
}
var ma = talib.MA(highs, 9) // use the moving average function "talib.MA" to calculate the moving average indicator
$.PlotLine("high_MA9", ma[ma.length - 2], r2[r2.length - 2].Time) // Use the line drawing library to draw the moving average indicator on the chart
Sleep(1000)
}
}
Test de retour:
Vous pouvez voir que la valeur moyenne de l'indicateur de la position du point de la souris dans la figure est 11466.9289
Le code ci-dessus peut être copié dans la stratégie pour exécuter le test, n'oubliez pas de vérifier la bibliothèque de lignes de dessin et de l'enregistrer!
La plateforme FMZ Quant dispose déjà d'une interface intégrée, à savoir le
exchange.GetRecords
fonction, pour obtenir des données de ligne K.
Ce qui suit se concentre sur l'accès direct à l'interface de données de ligne K de l'échange pour obtenir des données, car parfois vous devez spécifier des paramètres pour obtenir plus de lignes K, le paquetGetRecords
l'interface renvoie généralement 100 k lignes. si vous rencontrez une stratégie qui nécessite initialement plus de 100 K-lignes, vous devez attendre le processus de collecte.
Afin de faire fonctionner la stratégie le plus rapidement possible, vous pouvez encapsuler une fonction, accéder directement à l'interface de ligne K de l'échange, et spécifier des paramètres pour obtenir plus de données de ligne K.
En utilisant la paire de trading BTC_USDT sur Huobi comme exemple, nous mettons en œuvre cette exigence:
Trouvez la documentation de l'API de l'échange et consultez la description de l'interface K-line:
https://huobiapi.github.io/docs/spot/v1/en/#get-klines-candles
Paramètres:
Nom | Le type | Est-ce que c' est nécessaire? | Définition | Valeur |
---|---|---|---|---|
le symbole | une chaîne | vrai | Paire de négociation | Je ne sais pas. |
période | une chaîne | vrai | Renvoie la granularité temporelle des données, qui est l'intervalle de temps de chaque ligne k | 1 minute, 5 minutes, 15 minutes, 30 minutes, 60 minutes, 1 jour, 1 mois, 1 semaine, 1 année |
taille | nombre entier | faux | Renvoie le nombre de lignes de données K | [1, 2000] |
Code de test:
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")
}
Vous pouvez le voir sur le journal, imprimerrecords.length
est de 300, c'est-à-dire le nombre derecords
La barre de données de la ligne K est 300.