Produits secs 丨 Tutoriel de lecture des données historiques DolphinDB

Lorsqu'une stratégie quantitative est utilisée dans des transactions réelles, le programme qui traite les données en temps réel est généralement piloté par les événements. Lors du développement d'une stratégie quantitative, vous devez utiliser des données historiques pour le backtesting, et le programme à ce stade n'est généralement pas basé sur des événements. Par conséquent, la même stratégie nécessite l'écriture de deux ensembles de code, ce qui prend du temps et est source d'erreurs. Dans la base de données DolphinDB, les utilisateurs peuvent importer des données historiques dans la table de données en continu dans l'ordre chronologique sous la forme de "données en temps réel", de sorte que le même jeu de codes puisse être utilisé pour le backtesting et le trading réel.

Le cadre de traitement des données en continu de DolphinDB utilise un modèle de publication-abonnement-consommation. Les producteurs de données continuent de publier des données en temps réel pour tous les abonnés aux données sous forme de flux. Une fois que l'abonné a reçu le message, il peut utiliser une fonction personnalisée ou le moteur d'agrégation intégré de DolphinDB pour traiter le message. L'interface de données de streaming DolphinDB prend en charge les API dans plusieurs langages, notamment C ++, C #, Java et Python. Les utilisateurs peuvent utiliser ces API pour écrire une logique de traitement plus complexe et mieux s'intégrer à l'environnement de production réel. Les amis intéressés peuvent rechercher "DolphinDB Streaming Data Tutorial" pour en savoir plus.

Cet article présente les fonctions replay et replayDS, puis utilise des données financières pour montrer les scénarios de processus et d'application de la lecture de données.

1. Présentation des fonctions

rejouer

replay (inputTables, outputTables, [dateColumn], [timeColumn], [replayRate], [parallelLevel = 1])

La fonction de relecture est de lire plusieurs tables ou sources de données dans la table de sortie correspondante en même temps. L'utilisateur doit spécifier la table de données d'entrée ou la source de données, la table de sortie, la colonne de date, la colonne d'heure, la vitesse de lecture et le parallélisme.

Le concept des paramètres de la fonction de relecture est le suivant:

  • inputTables: Une seule table ou un tuple contenant plusieurs tables ou sources de données (voir introduction à replayDS).
  • outputTables: une seule table ou un tuple contenant plusieurs tables. Ces tables sont généralement des tables de données en continu. Le nombre de tables d'entrée et de tables de sortie est le même, et il existe une correspondance un à un, et la structure de chaque paire de tables d'entrée et de sortie est la même.
  • dateColumn, timeColumn: string, représente la colonne de date et d'heure de la table d'entrée, si elle n'est pas spécifiée, la première colonne est la colonne de date par défaut. Si la colonne d'heure dans la table d'entrée contient à la fois la date et l'heure, vous devez définir dateColumn et timeColumn sur la même colonne. Pendant la lecture, le système déterminera la précision temporelle minimale de la lecture en fonction des paramètres de dateColumn et timeColumn. Sous cette précision de temps, les données seront produites en même temps dans le même lot. Par exemple, une table a à la fois une colonne de date et une colonne d'heure, mais seule la dateColumn est définie dans la fonction de relecture, toutes les données du même jour seront sorties en un seul lot.
  • replayRate: Entier, représentant le nombre d'éléments de données rejoués par seconde. Étant donné que les données en même temps sont sorties dans le même lot pendant la lecture, lorsque le replayRate est inférieur au nombre de lignes dans un lot, le taux de sortie réel sera supérieur au replayRate.
  • parallelLevel: Entier, indiquant le parallélisme de la lecture des données. Lorsque la taille des données source dépasse la taille de la mémoire, la fonction replayDS doit être utilisée pour diviser les données source en plusieurs petites sources de données, puis lire les données du disque et les lire. La spécification de plusieurs threads pour lire les données peut augmenter la vitesse de lecture des données.

replayDS

replayDS (sqlObj, [dateColumn], [timeColumn], [timeRepartitionSchema])

La fonction replayDS peut convertir la requête SQL d'entrée en source de données et l'utiliser conjointement avec la fonction de relecture. Sa fonction est de diviser la requête SQL d'origine en plusieurs petites requêtes SQL dans l'ordre chronologique selon la partition de la table d'entrée et timeRepartitionSchema.

Le concept des paramètres de la fonction replayDS est le suivant:

  • sqlObj: méta code SQL, représentant les données à lire, comme <select * from sourceTable>.
  • dateColumn: chaîne, représentant la colonne de date. S'il n'est pas spécifié, la première colonne est la colonne de date par défaut. La colonne de date par défaut de la fonction replayDS est une colonne de partition de la source de données et la requête SQL d'origine est divisée en plusieurs requêtes en fonction des informations de partition.
  • timeColumn: chaîne, représentant la colonne d'heure, utilisée avec timeRepartitionSchema.
  • timeRepartitionSchema: vecteur de type d'heure, tel que 08:00:00 .. 18:00:00. Si timeColumn est spécifié en même temps, la requête SQL est ensuite fractionnée dans la dimension temporelle.

Lecture d'une seule table mémoire

La lecture d'une seule table mémoire n'a besoin que de définir la table d'entrée, la table de sortie, la colonne de date, la colonne d'heure et la vitesse de lecture.

replay (table d'entrée, table de sortie, `date,` heure, 10)

Lecture d'une seule table à l'aide d'une source de données

Lorsqu'il y a trop de lignes dans une seule table, vous pouvez utiliser replayDS pour la lecture. Tout d'abord, utilisez replayDS pour générer la source de données. Dans cet exemple, la colonne de date et timeRepartitionColumn sont spécifiées. L'appel de lecture est similaire à la lecture d'une seule table mémoire, mais le parallélisme de lecture peut être spécifié. L'implémentation interne de la relecture utilise le framework de pipeline, et la récupération et la sortie des données sont exécutées séparément. Lorsque l'entrée est une source de données, plusieurs blocs de données peuvent être lus en parallèle pour éviter d'attendre le thread de sortie. Dans cet exemple, le degré de parallélisme est défini sur 2, ce qui signifie que deux threads effectuent des opérations de récupération de données en même temps.

inputDS = replayDS (<select * from inputTable>, `date,` time, 08: 00: 00.000 + (1..10) * 3600000) 
replay (inputDS, outputTable, `date,` time, 1000, 2)

Lecture multi-table à l'aide d'une source de données

La relecture prend également en charge la lecture simultanée de plusieurs tables. Il vous suffit de passer plusieurs tables d'entrée pour les relire sous forme de tuples et de spécifier les tables de sortie séparément. Ici, la table de sortie et la table d'entrée doivent correspondre un à un, et chaque paire doit avoir la même structure de table. Si une colonne de date ou une colonne d'heure est spécifiée, il doit y avoir des colonnes correspondantes dans toutes les tables.

ds1 = replayDS (<select * from input1>, `date,` time, 08: 00: 00.000 + (1..10) * 3600000) 
ds2 = replayDS (<select * from input2>, `date,` time, 08 : 00: 00.000 + (1..10) * 3600000) 
ds3 = replayDS (<select * from input3>, `date,` time, 08: 00: 00.000 + (1..10) * 3600000) 
replay ([ds1 , ds2, ds3], [out1, out2, out3], `date,` heure, 1000, 2)

Annuler la lecture

Si la fonction de relecture est appelée par submitJob, vous pouvez utiliser getRecentJob pour obtenir le jobId, puis annuler la lecture avec cancelJob.

getRecentJobs () 
cancelJob (ID de travail)

S'il est appelé directement, vous pouvez utiliser getConsoleJobs pour obtenir le jobId dans une autre session GUI, puis utiliser cancelConsoleJob pour annuler la tâche de lecture.

getConsoleJobs () 
cancelConsoleJob (jobId)

2. Comment utiliser les données de lecture

Les données relues existent sous la forme de données en streaming. Nous pouvons utiliser les trois méthodes suivantes pour vous abonner et consommer ces données:

  • Abonnez-vous à DolphinDB et utilisez le script DolphinDB pour personnaliser la fonction de rappel afin de consommer des données en continu.
  • Abonnez-vous à DolphinDB et utilisez le moteur de calcul de streaming intégré pour traiter les données de streaming, telles que le moteur d'agrégation de séries chronologiques, le moteur d'agrégation de sections transversales, le moteur de détection d'anomalies, etc. Le moteur d'agrégation intégré de DolphinDB peut effectuer des calculs d'agrégation en temps réel sur les données en continu, ce qui est facile à utiliser et offre d'excellentes performances. En 3.2, nous utilisons le moteur d'agrégation transversale pour traiter les données rejouées et calculer la valeur intrinsèque de l'ETF. Pour l'utilisation spécifique du moteur d'agrégation de sections, veuillez vous référer au manuel d'utilisation de DolphinDB.
  • Les clients tiers s'abonnent et consomment des données via l'API de données en continu de DolphinDB.

3. Exemple financier

Rejouez les données de trading de niveau 1 du marché boursier américain pendant une journée et calculez la valeur de l'ETF

Dans cet exemple, les données de transaction de niveau 1 du marché boursier américain le 17 août 2007 sont utilisées, replayDS est utilisé pour la lecture des données et la valeur ETF est calculée via le moteur d'agrégation transversale intégré à DolphinDB. Les données sont stockées dans la table des citations de la base de données distribuée dfs: // TAQ. Ci-dessous se trouve la structure et l'aperçu des données de la table des citations.

// Chargez les données de la table quotes dans la base de données, vérifiez la structure de la table 
quotes = database ("dfs: // TAQ") .loadTable ("quotes"); 
quotes.schema (). ColDefs; 

nom typeString typeInt 
time SECOND 10 
symbol SYMBOL 17 
ofrsiz INT 4 
ofr DOUBLE 16 
mode INT 4 
mmid SYMBOL 17 
ex CHAR 2 
date DATE 6 
bidsize INT 4 
bid DOUBLE 16 

// Afficher les données des dix premières lignes du tableau des citations 
sélectionner les 10 premiers * à partir des citations; 

symbole date heure enchère ofr bidsiz ofrsiz mode ex mmid 
A 2007.08.17 04:15:06 0,01 0 10 0 12 80
A 2007.08.17 06:21:16 1 0 1 0 12 80 
A 2007.08.17 06:21:44 0.01 0 10 0 12 80 
A 2007.08.17 06:49:02 32.03 0 1 0 12 80 
A 2007.08.17 06 : 49: 02 32.03 32.78 1 1 12 80 
A 2007.08.17 07:02:01 18.5 0 1 0 12 84 
A 2007.08.17 07:02:01 18.5 45.25 1 1 12 84 
A 2007.08.17 07:54:55 31.9 45,25 3 1 12 84 
A 2007.08.17 08:00:00 31,9 40 3 2 12 84 
A 2007.08.17 08:00:00 31,9 35,5 3 2 12 84

(1) Divisez les données à lire. Comme il y a un total de 336 305 414 éléments de données en une journée, il y aura un long délai de relecture après avoir importé la mémoire une fois, et cela peut entraîner un dépassement de capacité de la mémoire. Par conséquent, utilisez d'abord la fonction replayDS et spécifiez le paramètre timeRepartitionSchema pour diviser les données en 62 parties en fonction de l'horodatage.

sch = sélectionner le nom, typeString comme type de quotes.schema (). colDefs 
trs = cutPoints (09: 30: 00.001..18: 00: 00.001, 60) 
rds = replayDS (<select * from quotes>, `date,` temps, très);

(2) Définissez la table de sortie outQuotes, qui est généralement une table de données de flux.

partager streamTable (100: 0, sch.name, sch.type) comme outQuotes

(3) Définissez les poids du dictionnaire des pondérations boursières et la fonction d'agrégation etfVal, qui sont utilisées pour calculer la valeur de l'ETF. Dans cet exemple, nous calculons uniquement la valeur ETF d'AAPL, IBM, MSFT, NTES, AMZN et GOOG.

defg etfVal (poids, sym, prix) { 
    return wsum (prix, poids [sym]) 
} 
poids = dict (STRING, DOUBLE) 
poids [`AAPL] = 0,1 
poids [` IBM] = 0,1 
poids [`MSFT] = 0,1 
poids [`NTES] = 0,1 
poids [` AMZN] = 0,1 
poids [`GOOG] = 0,5

(4) Créez un moteur d'agrégation de flux et abonnez-vous à la table de sortie outQuotes pour la lecture des données. Lors de l'abonnement à la table outQuotes, nous spécifions les conditions de filtrage pour la table de publication. Seules les données portant le symbole AAPL, IBM, MSFT, NTES, AMZN, GOOG seront publiées dans le moteur d'agrégation de sections, ce qui réduira la surcharge inutile du réseau et la transmission de données.

setStreamTableFilterColumn (outQuotes, `symbol) 
outputTable = table (1: 0,` time`etf, [TIMESTAMP, DOUBLE]) 
tradesCrossAggregator = createCrossSectionalAggregator ("etfvalue", <[etfVal {poids} (symbole, ofr)]>, guillemets, guillemets outputTable, `symbol,` perBatch) 
subscribeTable (, "outQuotes", "tradesCrossAggregator", - 1, append! {tradesCrossAggregator}, true ,,,,, `AAPL`IBM`MSFT`NTES`AMZN`GOOG)

(5) Démarrez la lecture, réglez la lecture sur 100 000 données par seconde, et le moteur d'agrégation consommera les données de lecture en temps réel.

submitJob ("replay_quotes", "replay_quotes_stream", replay, [rds], [`outQuotes],` date, `time, 100000,4)

(6) Visualisez la valeur ETF de l'action que nous avons sélectionnée à différents moments.

// Afficher les 15 premières lignes de données dans le tableau outputTable, où l'heure dans la première colonne est l'heure à laquelle le calcul d'agrégation a eu lieu 
> sélectionnez les 15 premiers * dans outputTable; 

time etf 
2019.06.04T16: 40: 18.476 14.749 
2019.06.04T16: 40: 19.476 14.749 
2019.06 .04T16: 40: 20.477 14.749 
2019.06.04T16: 40: 21.477 22.059 
2019.06.04T16: 40: 22.477 22.059 
2019.06.04T16: 40: 23.477 34.049 
2019.06.04T16: 40: 24.477 34.049 
2019.06.04T16: 40: 25.477 284.214 
2019.06.04T16 : 40: 22.4774.214 2019.06.04T16 : 40: 22.4774.214 2019.06.04T16 : 40: 22.4774.214 : 40: 26.477 284.214 
2019.06.04T16: 40: 27.477 285.68 
2019.06.04T16: 40: 28.477 285.68 
2019.06.04T16: 40: 29.478 285.51 
2019.06.04T16: 40: 30.478 285.51 
2019.06.04T16: 40: 31.478 285.51 
2019.06.04 : 32,478 285,51

4. Test de performance

Nous avons réalisé un test de performance sur la fonction de lecture de données de DolphinDB sur le serveur. La configuration du serveur est la suivante:

Hôte: DELL PowerEdge R730xd

Processeur: CPU Intel Xeon (R) E5-2650 v4 (24 cœurs 48 threads 2,20 GHz)

Mémoire: 512 Go (32 Go × 16, 2666 MHz)

Disque dur: disque dur 17T (1,7T × 10, vitesse de lecture 222 Mo / s, vitesse d'écriture 210 Mo / s)

Réseau: 10 Gigabit Ethernet

Le script de test est le suivant:

sch = sélectionner le nom, typeString comme type de quotes.schema (). colDefs 
trs = cutPoints (09: 30: 00.001..18: 00: 00.001,60) 
rds = replayDS (<select * from quotes>, `date,` temps, très); 
partager streamTable (100: 0, sch.name, sch.type) comme outQuotes 
jobid = submitJob ("replay_quotes", "replay_quotes_stream", replay, [rds], [`outQuotes],` date, `time`` 4)

Lorsque la vitesse de lecture n'est pas définie (c'est-à-dire la lecture à la vitesse la plus rapide) et qu'il n'y a pas d'abonnement à la table de sortie, il ne faut que 90 à 110 secondes pour lire 336 305 414 éléments de données.


Je suppose que tu aimes

Origine blog.51cto.com/15022783/2590411
conseillé
Classement