Lors de la rédaction d'une stratégie de négociation programmatique, il est souvent nécessaire d'utiliser des données K-cycle non standard, par exemple des données K-cycle de 12 minutes ou de 4 heures, qui ne sont généralement pas directement disponibles. La réponse est certainement qu'il y a une solution. Les cycles non standard peuvent être obtenus en combinant les données de cycles plus petits, en imaginant que le prix le plus élevé de plusieurs cycles est calculé comme le prix le plus élevé après la synthèse, le prix le plus bas est calculé comme le prix le plus bas après la synthèse, le prix d'ouverture ne change pas. Le premier prix d'ouverture est calculé à partir des données de base de la ligne K, le prix de clôture correspond au dernier prix de clôture des données de base de la ligne K, le temps est le temps nécessaire pour le prix d'ouverture, le volume de transactions est calculé et obtenu à partir des données de base. Voici ce qu'il en est:
Nous prenons l'exemple de BTC_USDT, le marché des actifs de la blockchain, où une heure devient quatre heures.
Le temps | haut | Elle est ouverte. | bas | Récupération |
---|---|---|---|---|
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 |
Ces quatre cycles d'une heure sont synthétisés en une racine de quatre cycles d'une heure, et le prix d'ouverture est le prix d'ouverture du premier cycle à 00:00: 11382.57. Le prix de clôture est le dernier, c'est-à-dire le prix de clôture à 03:00:11384.71. Le prix le plus élevé est ici: 11447.07 Le prix le plus bas est le prix le plus bas ici: 11365.51 Le cycle de 4 heures commence à 00:00 et la ligne K de 1 heure commence à 2019.8.12 00:00 Le montant des transactions par heure (l'observation principale de la synthèse des prix n'est pas indiquée dans les données de transactions) n'est pas présenté ici.
Le résultat est une ligne K de 4 heures: hauteur: 11447 Il est ouvert: 11382.57 Basse: 11365.51 Résultats: 11384.71 Il est temps: 08.12.2019.
Les données sont cohérentes.
Une fois que l'idée initiale a été vérifiée, il est possible d'écrire du code manuellement pour réaliser ce besoin.
Le code est disponible directement, et il est uniquement destiné à l'apprentissage de référence:
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线接口获取数据过于频繁,导致交易所限制。
}
}
En fait, pour synthétiser des lignes K, il faut deux choses, la première est que vous avez besoin de données de matière première, c'est-à-dire des données de lignes K de petites cycles, comme dans l'exemple précédent.var r = exchange.GetRecords()
Les données de ligne K de petites périodes sont obtenues. Deuxièmement, il est nécessaire de déterminer quelle période est la plus grande, c'est-à-dire la période cible pour la synthèse des données de ligne K.
L'algorithme de la fonction GetNewCycleRecords est ensuite utilisé pour finalement retourner les données d'une structure d'arithmétiques K-lignes synthétisées.
Il est important de noter que:
1, le cycle cible ne peut pas être inférieur au cycle de la ligne K de la fonction GetNewCycleRecords que vous passez comme matière première. Il n'est pas possible de synthétiser des données de cycles plus petits avec des cycles plus petits.
Les cycles cibles doivent être fermés.
Qu'est-ce qu'un cycle de fermeture?
En termes simples, c'est un cercle fermé où les intervalles de temps des cycles cibles se combinent en une heure ou en une journée.
Par exemple:
Par exemple, la ligne K d'un cycle de 12 minutes, qui commence à 0 minutes et 0 secondes de chaque heure (par exemple à 0 heures), le premier cycle est00:00:00 ~ 00:12:00
Le deuxième cycle est00:12:00 ~ 00:24:00
Le troisième cycle est00:24:00 ~ 00:36:00
Le quatrième cycle est00:36:00 ~ 00:48:00
Le cinquième cycle est00:48:00 ~ 01:00:00
Le blogueur a écrit: "C'est une heure complète.
Si c'est un cycle de 13 minutes, c'est-à-dire un cycle non fermé, les données calculées pour ce cycle ne sont pas uniques, car selon le point de départ des données synthétisées, les données synthétisées diffèrent.
Le disque virtuel fonctionne:
Comparer les échanges
J'ai souvent des amis qui me demandent comment calculer la moyenne du prix le plus élevé pour chaque ligne K.
Généralement, nous calculons les moyennes qui sont les moyennes des prix de clôture calculés et qui constituent la moyenne, mais il est parfois nécessaire de calculer les prix les plus élevés, les prix les plus bas, les prix d'ouverture, etc.
Il n'y a pas de moyen de le faire directement.exchange.GetRecords()
Les données de la ligne K retournées par la fonction sont transmises directement à la fonction de calcul de l'indicateur.
Par exemple:talib.MALa fonction de calcul de l'indicateur homogène a deux paramètres, le premier paramètre étant les données à transmettre et le second paramètre étant le paramètre de cycle de l'indicateur. Par exemple, nous allons calculer les indicateurs suivants.
Le cycle de la ligne K est de 4 heures. Sur le graphique de l'échange, une ligne moyenne a été définie avec un paramètre de cycle de la ligne moyenne de 9. La source de données calculée est le prix le plus élevé par bar.C'est-à-dire que cette ligne moyenne est la moyenne calculée en moyenne des prix les plus élevés de 9 cycles de 4 heures de la ligne KBar, composée d'une ligne moyenne d'indicateurs.
Nous avons commencé à construire nous-mêmes un calcul de données pour voir si c'était le même que celui des graphiques des bourses.
var highs = []
for (var i = 0 ; i < r2.length ; i++) {
highs.push(r2[i].High)
}
Puisque l'on doit calculer la valeur moyenne du prix le plus élevé pour chaque Bar, on obtient un indicateur de ligne moyenne. Il faut alors construire une matrice dans laquelle chaque élément de données correspond à la valeur la plus élevée de chaque bar. On peut voir que les variables highs commencent comme une matrice vide, puis on parcourt cette variable de données de ligne K, r2 (vous ne vous souvenez pas de r2? Lire la valeur la plus élevée de r2 par Bar (c'est-à-dire r2[i].High, i prend une valeur dans la gamme de 0 à r2.length-1), puis pousser vers les hauts.
À ce stade, les hauts peuvent être passés dans talib.
L'exemple le plus complet:
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)
}
}
Le dépistage est en cours:
Vous pouvez voir que les valeurs de l'indicateur de la ligne moyenne où la souris s'arrête dans le graphique sont11466.9289
Le code ci-dessus peut être copié pour exécuter le test dans la stratégie, et n'oubliez pas de cocher "Library de lignes de dessin" pour le sauvegarder!
La plate-forme de trading quantitatif de l'inventeur est déjà équipée d'une interface enveloppée, la fonction exchange.GetRecords, qui permet d'obtenir des données de ligne K. L'accent est mis sur l'accès direct à l'interface de données de ligne K de l'échange pour obtenir des données, car il est parfois nécessaire de spécifier des paramètres pour obtenir plus de lignes K, enveloppé dans l'interface GetRecords Généralement, il renvoie 100 clés. Si une stratégie nécessite plus de 100 clés au départ, elle doit être collectée en attente. Pour que la stratégie fonctionne le plus rapidement possible, vous pouvez envelopper une fonction vous-même, 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.
Nous avons réalisé ce besoin en utilisant la paire de transactions BTC_USDT comme exemple:
Pour trouver la documentation de l'API de l'échange, voir la description de l'interface K-Line:
https://api.huobi.pro/market/history/kline?period=1day&size=200&symbol=btcusdt
Paramètres:
Nom du paramètre | Le type | Est-ce vraiment nécessaire? | Décrire | Prise de valeur |
---|---|---|---|---|
le symbole | une chaîne | vrai | Les échanges | Je ne sais pas. |
période | une chaîne | vrai | Retournez le grain de temps des données, c'est-à-dire l'intervalle de temps entre chaque ligne. | 1 minute, 5 minutes, 15 minutes, 30 minutes, 60 minutes, 1 jour, 1 mois, 1 semaine, 1 année |
taille | nombre entier | faux | Retournez le nombre de lignes de données K | [1, 2000] |
Le 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")
}
La version Python, un exemple d'interface pour accéder à un échange de jetons:
#!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画线类库
La version Python, exemple d'interface K-Line pour accéder à l'échange:
#!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画线类库
Comme vous pouvez le voir sur le journal, imprimer records.length est 300, c'est-à-dire que les records K contiennent un nombre de barres de données de ligne 300.
les garde-corpsEt si le postmaster résout le problème? On ne peut pas synthétiser le jour k en 3 heures ou 6 heures.
les garde-corpsif (((1000 * 60 * 60 * 24) - sourceRecords[i].Time % (1000 * 60 * 60 * 24) + (n * 1000 * 60)) % targetCycle == 0) { estBegin = vrai Je ne sais pas. Il y a un problème avec cette phrase, vous ne pouvez pas synthétiser le jour k avec 3 heures ou 6 heures, vous pouvez seulement synthétiser le jour k avec 1 heure, 2 heures et 4 heures.
Le groupe xis2004Si vous voulez grimper sur une espèce, est-ce que vous pouvez grimper sur toutes les données historiques?
Je veux.Merci pour votre réponse.
Je veux.S'il vous plaît, comment gérer mieux si vous voulez plus de 300 bits? Par exemple, 1000 bits de données K.
L'inventeur de la quantification - un petit rêveBien, je vais prendre le temps de le modifier.
L'inventeur de la quantification - un petit rêveIl s'agit de l'accès aux données de l'interface de l'échange, la quantité de données que l'échange vous donne.
L'inventeur de la quantification - un petit rêveSi le nombre de retours maximaux pris en charge par l'interface de l'échange est dépassé, il ne peut être collecté que suffisamment de données de ligne K.