[PYTHON] J'ai essayé de résumer les méthodes qui sont souvent utilisées lors de l'implémentation d'algo de base dans Quantx Factory

Auto-introduction

Je m'appelle Masukawa (https://www.facebook.com/ryozodesert) et je suis stagiaire chez SmartTrade Co., Ltd.. .. J'étudie l'apprentissage automatique.

Qu'est-ce que QuantX Factory?

Smart Trade Co., Ltd.

Démocratie financière

Sur la base de cette philosophie, nous avons développé "QuantX Factory", une plate-forme sur laquelle tout le monde peut facilement développer des algorithmes de trading.

Forces

Sujet principal

Au cours de mon premier mois en tant que stagiaire, j'expliquerai comment utiliser les méthodes pandas et talib qui sont fréquemment utilisées dans la création d'algorithmes pour implémenter des indicateurs techniques de base tels que MACD, moyennes mobiles et RSI.

(Remarque: vous n'êtes pas obligé de bien comprendre le contenu de ce code pour le moment) </ font>

#Importation de bibliothèque
#Bibliothèque requise
#Importer le moteur de backtest "maron"
import maron
import maron.signalfunc as sf
import maron.execfunc as ef
#Bibliothèque supplémentaire
#Si vous avez besoin de bibliothèques supplémentaires, ajoutez-les selon l'exemple ci-dessous.
#Importez l'outil d'analyse de données "pandas" et utilisez-le sous le nom "pd"
import pandas as pd
#Importez le jeu de fonctions financières "talib" et utilisez-le avec le nom "ta"
import talib as ta
import numpy as np
#Importez "" et utilisez-le comme ""
# import  as 

#Méthode de commande(Veuillez décommenter un seul des trois suivants selon la méthode de commande souhaitée)
# ot = maron.OrderType.MARKET_CLOSE  #Ordre au moment du cours de clôture le lendemain de l'émission du signal
ot = maron.OrderType.MARKET_OPEN   #Commande au moment du cours d'ouverture le lendemain de l'émission du signal
# ot = maron.OrderType.LIMIT         #Limiter l'ordre

def initialize(ctx):  #Partie d'initialisation
  ctx.logger.debug("initialize() called")  #Sortie de journal
  ctx.target = 0.1
  ctx.loss_cut = -0.02
  ctx.plofit = 0.05
  
  ctx.configure(
      channels={
        "jp.stock": {
          "symbols": [
            "jp.stock.2914", #JT(L'industrie japonaise du tabac)
            "jp.stock.8766", #Tokio Marine Holdings
            "jp.stock.8031", #Mitsui Bussan
            "jp.stock.8316", #Groupe financier Sumitomo Mitsui
            "jp.stock.8411", #Groupe financier Mizuho
            "jp.stock.9437", #NTT Docomo
            "jp.stock.4502", #Industrie pharmaceutique Takeda
            "jp.stock.8058", #Mitsubishi Corporation
            "jp.stock.9433", #KDDI
            "jp.stock.9432", #Téléphone Nippon Telecom
            "jp.stock.7267", #Honda (Honda Giken Kogyo)
            "jp.stock.8306", #Groupe financier Mitsubishi UFJ
            "jp.stock.4503", #Astellas Pharmaceutical
            "jp.stock.4063", #Industrie chimique Shinetsu
            "jp.stock.7974", #Nintendo
            "jp.stock.6981", #Murata Seisakusho
            "jp.stock.3382", #Seven & i Holdings
            "jp.stock.9020", #Chemin de fer de passagers de l'est du Japon
            "jp.stock.8802", #Domaine Mitsubishi
            "jp.stock.9022", #Chemin de fer de passagers de Tokai
            "jp.stock.9984", #Groupe Softbank
            "jp.stock.6861", #Keyence
            "jp.stock.6501", #Hitachi, Ltd.
            "jp.stock.6752", #Panasonic
            "jp.stock.6758", #Sony
            "jp.stock.6954", #Fanac
            "jp.stock.7203", #Moteur Toyota
            "jp.stock.7751", #Canon
            "jp.stock.4452", #Kao
            "jp.stock.6098", #Recruter Holdings
          ],
          #⑥
          "columns": ["close_price_adj",    #le dernier prix(Après ajustement pour le fractionnement d'actions) 
          ]}})
  
  def _my_signal(data):  #Acheter et vendre une partie de génération de signal
    #Si vous souhaitez vérifier le contenu des données, veuillez décommenter ci-dessous
    # ctx.logger.debug(data)

    syms = data.minor_axis   #Créer une liste de stock
    dates = data.major_axis  #Créer une liste de dates
    
    '''↓ Ecrire le code pour obtenir les données nécessaires au calcul logique à partir des données de la structure 3D ↓'''
    cp = data["close_price_adj"].fillna("ffill")
    '''↑ Ecrire le code pour obtenir les données nécessaires au calcul logique à partir des données de la structure 3D ↑'''
    
    '''↓ Ecrire le code pour calculer la logique nécessaire pour définir les conditions de trading ↓'''
    
    
    movave5 = cp.rolling(window = 5, center = False).mean()
    movave25 = cp.rolling(window = 25, center = False).mean()
    
    '''↑ Ecrire le code pour calculer la logique nécessaire pour définir les conditions de trading ↑'''
    
    #Définir les signaux d'achat et de vente(Retour en tant que valeur booléenne)
    buy_sig = (movave5 > movave25) & (movave5.shift(1) < movave25.shift(1))
    sell_sig =  (movave5 < movave25) & (movave5.shift(1) > movave25.shift(1))

    # market_Tous les 0 appelés sig.Créez un bloc de données "horizontal: nom de la marque, vertical: date" qui stocke 0
    market_sig = pd.DataFrame(data=0.0, columns=syms, index=dates)
    
    # buy_1 quand sig est vrai.0、sell_Quand sig est vrai-1.0, 0 lorsque les deux sont Vrai.Mettre à 0
    market_sig[buy_sig == True] = 1.0
    market_sig[sell_sig == True] = -1.0
    market_sig[(buy_sig == True) & (sell_sig == True)] = 0.0

    # market_Si vous souhaitez vérifier le contenu de sig, veuillez décommenter ci-dessous
    # ctx.logger.debug(market_sig)

    return {
      "buy:sig":buy_sig,
      "sell:sig": sell_sig,
      "market:sig": market_sig,
      #Veuillez ajouter les données que vous souhaitez afficher dans le tableau des résultats du backtest ci-dessous
      
    }
      
  ctx.regist_signal("my_signal", _my_signal)  #Enregistrement du signal

def handle_signals(ctx, date, current):  #Partie de traitement quotidien
  '''
  current: pd.DataFrame
  '''
  #initialiser_my_Commercialiser le signal généré par le signal_Magasin dans sig
  market_sig = current["market:sig"]
  done_syms = set([])  #Type de set qui stocke les stocks pour lesquels le règlement des bénéfices et la réduction des pertes ont été effectués
  none_syms = set([])  # portfolio.Définissez le type qui stocke les marques qui n'existent pas dans des positions
  # portfolio.positions(Marques que vous possédez)Actions cibles(sym)Vérifiez s'il y a
  for (sym, val) in market_sig.items():
    if sym not in ctx.portfolio.positions:
      none_syms.add(sym)
  # portfolio.positions(Marques que vous possédez)Chaque marque de(sym)Vérifiez si le nombre d'actions détenues par
  for (sym, val) in ctx.portfolio.positions.items():
    if val["amount"] == 0:
      none_syms.add(sym)
  #Réduction des pertes, règlement des bénéfices(Rentabilité)paramètres de
  #Processus itératif pour vérifier les stocks que vous possédez un par un
  for (sym, val) in ctx.portfolio.positions.items():
    #Acquisition du ratio profit / perte
    returns = val["returns"]
    if returns < -0.03:  #Ratio profit / perte-3%Moins que(Valeur absolue 3%Plus grande perte)dans le cas de
      #Ordre de vente pour réduction des pertes
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="Coupe de perte(%f)" % returns)
      #Ajout du problème affecté à sym au type d'ensemble qui stocke le problème pour lequel le règlement des bénéfices et la réduction des pertes ont été effectués.
      done_syms.add(sym)
    elif returns > 0.05:  #Ratio profit / perte+5%Si supérieur à
      #Prise de bénéfices(Rentabilité)Ordre de vente pour
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="Vente à but lucratif(%f)" % returns)
      #Ajout du problème affecté à sym au type d'ensemble qui stocke le problème pour lequel le règlement des bénéfices et la réduction des pertes ont été effectués.
      done_syms.add(sym)
  buy = market_sig[market_sig > 0.0]  #Acheter signal
  for (sym, val) in buy.items():  #Traitez les actions avec les signaux d'achat un par un
    # done_syms ou aucun_Si syms a sym
    if sym in done_syms:
      continue  #Ignorer le traitement
    #Acheter la commande
    sec = ctx.getSecurity(sym)
    sec.order(sec.unit() * 1, orderType=ot, comment="SIGNAL BUY")
    #Si vous souhaitez afficher le journal des commandes d'achat ci-dessous, veuillez supprimer les commentaires ci-dessous(Attention à long terme)
    #ctx.logger.debug("BUY: %s,  %f" % (sec.code(), val))
  sell = market_sig[market_sig < 0.0]  #Signal de vente
  for (sym, val) in sell.items():  #Traitez les actions avec les signaux de vente un par un
    # done_syms ou aucun_Si syms a sym
    if (sym in done_syms) | (sym in none_syms):
      continue  #Ignorer le traitement
    #Ordre de vente
    sec = ctx.getSecurity(sym)
    sec.order(sec.unit() * -1,orderType=ot, comment="SIGNAL SELL")

Figure 1: Algorithme utilisant la croix dorée et la croix morte de la ligne moyenne mobile (voir: https://factory.quantx.io/developer/149d79a8cf744f059af0e96918913a9f/coding / codage))

série pandas

** méthode de roulement **

pd.DataFrame.rolling(window)

  • Une méthode utilisée pour appliquer des fonctions de fenêtre aux structures de données pandas de base telles que DataFrame et Series, qui retourne un objet roulant.
  • Le principal argument utilisé est window, qui définit le nombre de fenêtres. --Fonction de fenêtre: Une fonction qui devient 0 sauf pour un certain intervalle fini </ font>.

Exemple: implémenter une moyenne mobile sur 25 jours

Dans la ligne 82 de la Fig. movave25 = cp.rolling(window = 25).mean() Cela dit, mais c'est ce qui définit la moyenne mobile sur 25 jours.

  1. Appliquez la fonction de fenêtre avec 25 fenêtres avec cp.rolling (window = 25) to cp, qui est un DataFrame qui stocke le prix de clôture de chaque date de chaque marque, et un objet roulant est retourné.
  2. Appliquez la méthode moyenne à l'objet roulant renvoyé pour renvoyer un nouvel objet de type DataFrame contenant la valeur moyenne pendant 25 jours.

Vous disposez maintenant de move25, un DataFrame qui stocke 25 jours de moyennes mobiles.

méthode de décalage

pandas.DataFrame.shift(periods)

--Retourne un objet DataFrame, une méthode qui déplace (décale) les données stockées dans un bloc de données par périodes </ font> --Utilisation: détecte les changements dans la relation d'amplitude entre les deux lignes de moyenne mobile, la ligne à court terme et la ligne à long terme, à partir de la veille.

Exemple: Jugement de la croix d'or et de la croix morte Dans la ligne 87 de la Fig. buy_sig = (movave5 > movave25) & (movave5.shift(1) < movave25.shift(1)) Cependant, ce code indique que "la moyenne mobile sur 5 jours du jour est supérieure à la moyenne mobile sur 25 jours et la moyenne mobile sur 5 jours du jour précédent est plus petite que la moyenne mobile sur 25 jours", c'est-à-dire une croix en or. Je suis. La ligne 88 est le contraire.

La méthode de décalage est utilisée de cette manière.

système talib

Qu'est-ce que le talib en premier lieu?

Une bibliothèque qui vous permet d'implémenter facilement des indicateurs techniques. Veuillez vous référer à l'URL suivante pour les indicateurs qui peuvent être mis en œuvre. https://mrjbq7.github.io/ta-lib/funcs.html

Exemple d'utilisation du talib

# Sample Algorithm
#Importation de bibliothèque
#Bibliothèque requise
import maron
import maron.signalfunc as sf
import maron.execfunc as ef
#Bibliothèque supplémentaire
#Veuillez consulter les notes sur l'écran de droite pour les bibliothèques qui peuvent être utilisées ①



import pandas as pd
import talib as ta
import numpy as np

#Méthode de commande(Veuillez décommenter un seul des deux suivants selon la méthode de commande souhaitée)
#Veuillez consulter la note sur l'écran de droite pour la méthode de commande ②
#ot = maron.OrderType.MARKET_CLOSE #Ordre au moment du cours de clôture le lendemain de l'émission du signal
ot = maron.OrderType.MARKET_OPEN   #Commande au moment du cours d'ouverture le lendemain de l'émission du signal
#ot = maron.OrderType.LIMIT        #Limiter l'ordre

#Acquisition de stocks et de colonnes
#Veuillez consulter la note sur l'écran de droite pour la désignation de la marque ③
#Veuillez consulter la note sur l'écran de droite pour obtenir les colonnes ④
def initialize(ctx):
  #Réglage
  ctx.logger.debug("initialize() called")
  ctx.configure(
    channels={               #Canal utilisé
      "jp.stock": {
        "symbols": [
            "jp.stock.2914", #JT(L'industrie japonaise du tabac)
            "jp.stock.8766", #Tokio Marine Holdings
            "jp.stock.8031", #Mitsui Bussan
            "jp.stock.8316", #Groupe financier Sumitomo Mitsui
            "jp.stock.8411", #Groupe financier Mizuho
            "jp.stock.9437", #NTT Docomo
            "jp.stock.4502", #Industrie pharmaceutique Takeda
            "jp.stock.8058", #Mitsubishi Corporation
            "jp.stock.9433", #KDDI
            "jp.stock.9432", #Téléphone Nippon Telecom
            "jp.stock.7267", #Honda (Honda Giken Kogyo)
            "jp.stock.8306", #Groupe financier Mitsubishi UFJ
            "jp.stock.4503", #Astellas Pharmaceutical
            "jp.stock.4063", #Industrie chimique Shinetsu
            "jp.stock.7974", #Nintendo
            "jp.stock.6981", #Murata Seisakusho
            "jp.stock.3382", #Seven & i Holdings
            "jp.stock.9020", #Chemin de fer de passagers de l'est du Japon
            "jp.stock.8802", #Domaine Mitsubishi
            "jp.stock.9022", #Chemin de fer de passagers de Tokai
            "jp.stock.9984", #Groupe Softbank
            "jp.stock.6861", #Keyence
            "jp.stock.6501", #Hitachi, Ltd.
            "jp.stock.6752", #Panasonic
            "jp.stock.6758", #Sony
            "jp.stock.6954", #Fanac
            "jp.stock.7203", #Moteur Toyota
            "jp.stock.7751", #Canon
            "jp.stock.4452", #Kao
            "jp.stock.6098", #Recruter Holdings
        ],
        "columns": [
          "close_price",     #le dernier prix
          "close_price_adj", #le dernier prix(Après ajustement pour le fractionnement d'actions)
          #"volume_adj",     #Le volume
          #"txn_volume",     #Prix de négociation
        ]
      }
    }
  )
  
  #Définition du signal
  def _my_signal(data):
    #Obtenez des données sur les prix de clôture
    cp=data["close_price_adj"].fillna(method="ffill")
    
    syms = data.minor_axis   #Créer une liste de stock
    dates = data.major_axis  #Créer une liste de dates
   
    #Où stocker les données
    macd = pd.DataFrame(data=0.0, columns=syms, index=dates)
    macdsignal = pd.DataFrame(data=0.0, columns=syms, index=dates)
    macdhist = pd.DataFrame(data=0.0, columns=syms, index=dates)
    rsi = pd.DataFrame(data = 0.0, columns = syms, index = dates)

    #TA-Calcul de MACD par Lib
    for (sym,val) in cp.items():
      macd[sym],macdsignal[sym],macdhist[sym] = ta.MACD(cp[sym])
      rsi[sym] = ta.RSI(cp[sym].values.astype(np.double), timeperiod = 10)

    
    macd_golden = (macd > macdsignal) & (macd.shift(1) < macdsignal.shift(1))
    macd_dead = (macd < macdsignal) & (macd.shift(1) > macdsignal.shift(1))
    
    #Acheter et vendre une partie de génération de signal
    
    buy_sig = macd_golden | (rsi < 30)
    sell_sig = macd_dead | (rsi > 70)

    #market_Créez un bloc de données appelé sig qui contient tous les 0
    market_sig = pd.DataFrame(data=0.0, columns=syms, index=dates)
    
    #buy_1 quand sig est vrai.0、sell_Quand sig est vrai-1.Mettre à 0
    market_sig[buy_sig == True] = 1.0
    market_sig[sell_sig == True] = -1.0
    market_sig[(buy_sig == True) & (sell_sig == True)] = 0.0
    # ctx.logger.debug(market_sig)

    return {
      "MACD:g2": macd, 
      "MACDSignal:g2": macdsignal, 
      "MACDHist": macdhist, 
      "market:sig": market_sig,
    }

  #Enregistrement du signal
  ctx.regist_signal("my_signal", _my_signal)

def handle_signals(ctx, date, current):  #Partie de traitement quotidien
  '''
  current: pd.DataFrame
  '''
  #initialiser_my_Commercialiser le signal généré par le signal_Magasin dans sig
  market_sig = current["market:sig"]
  done_syms = set([])  #Type de set qui stocke les stocks pour lesquels le règlement des bénéfices et la réduction des pertes ont été effectués
  none_syms = set([])  # portfolio.Définissez le type qui stocke les marques qui n'existent pas dans des positions
  # portfolio.positions(Marques que vous possédez)Actions cibles(sym)Vérifiez s'il y a
  for (sym, val) in market_sig.items():
    if sym not in ctx.portfolio.positions:
      none_syms.add(sym)
  # portfolio.positions(Marques que vous possédez)Chaque marque de(sym)Vérifiez si le nombre d'actions détenues par
  for (sym, val) in ctx.portfolio.positions.items():
    if val["amount"] == 0:
      none_syms.add(sym)
  #Réduction des pertes, règlement des bénéfices(Rentabilité)paramètres de
  #Processus itératif pour vérifier les stocks que vous possédez un par un
  for (sym, val) in ctx.portfolio.positions.items():
    #Acquisition du ratio profit / perte
    returns = val["returns"]
    if returns < -0.03:  #Ratio profit / perte-3%Moins que(Valeur absolue 3%Plus grande perte)dans le cas de
      #Ordre de vente pour réduction des pertes
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="Coupe de perte(%f)" % returns)
      #Ajout du problème affecté à sym au type d'ensemble qui stocke le problème pour lequel le règlement des bénéfices et la réduction des pertes ont été effectués.
      done_syms.add(sym)
    elif returns > 0.05:  #Ratio profit / perte+5%Si supérieur à
      #Prise de bénéfices(Rentabilité)Ordre de vente pour
      sec = ctx.getSecurity(sym)
      sec.order(-val["amount"], comment="Vente à but lucratif(%f)" % returns)
      #Ajout du problème affecté à sym au type d'ensemble qui stocke le problème pour lequel le règlement des bénéfices et la réduction des pertes ont été effectués.
      done_syms.add(sym)
  buy = market_sig[market_sig > 0.0]  #Acheter signal
  for (sym, val) in buy.items():  #Traitez les actions avec les signaux d'achat un par un
    # done_syms ou aucun_Si syms a sym
    if sym in done_syms:
      continue  #Ignorer le traitement
    #Acheter la commande
    sec = ctx.getSecurity(sym)
    sec.order(sec.unit() * 1, orderType=ot, comment="SIGNAL BUY")
    #Si vous souhaitez afficher le journal des commandes d'achat ci-dessous, veuillez supprimer les commentaires ci-dessous(Attention à long terme)
    #ctx.logger.debug("BUY: %s,  %f" % (sec.code(), val))
  sell = market_sig[market_sig < 0.0]  #Signal de vente
  for (sym, val) in sell.items():  #Traitez les actions avec les signaux de vente un par un
    # done_syms ou aucun_Si syms a sym
    if (sym in done_syms) | (sym in none_syms):
      continue  #Ignorer le traitement
    #Ordre de vente
    sec = ctx.getSecurity(sym)
    sec.order(sec.unit() * -1,orderType=ot, comment="SIGNAL SELL")

Figure 2: Algorithme utilisant la croix dorée RSI et MACD et la croix morte (voir: https://factory.quantx.io/developer/6ba1eb1b748d46a18ce128fea3156282/coding / codage))

RSI talib.RSI(close, timeperiod = 14)

――RSI est un indice technique qui fait la distinction entre «surachat» et «survente».

  • Prenez une fermeture d'objet np.double type np.arrays qui indique le cours de clôture et la période de temps qui indique la période comme arguments.

Exemple: à la ligne 82 du code de la figure 2.

rsi = pd.DataFrame(data = 0.0, columns = syms, index = dates)

Définir un DataFrame pour stocker le RSI de chaque problème

Pour le relevé à la ligne 85

for (sym,val) in cp.items():
      rsi[sym] = ta.RSI(cp[sym].values.astype(np.double), timeperiod = 10)

Le RSI de chaque marque est stocké dans.

  • Comme cp [sym] est un objet de type DataFrame, convertissez-le en objet de type tableau avec cp [sym] .values. --Et cp [sym] .values.astype (np.double) convertit le contenu du tableau en type np.double. --Cette fois, nous prendrons RSI pendant 10 jours, définissez donc timeperiod = 10.
  • Juger l'achat et la vente en faisant référence à «survendu» ou «surachat»

MACD ta.MACD(close)

――Il s'agit d'un indice technique qui applique la ligne de moyenne mobile et mesure le moment de l'achat et de la vente en combinant la ligne MACD et la ligne japonaise de la ligne de signal MACD.

  • Fermez un objet Series qui stocke le cours de clôture de l'émission comme argument. --Retourne trois objets de type DataFrame

Exemple: aux lignes 79-81 du code de la figure 2.

macd = pd.DataFrame(data=0.0, columns=syms, index=dates)
macdsignal = pd.DataFrame(data=0.0, columns=syms, index=dates)
macdhist = pd.DataFrame(data=0.0, columns=syms, index=dates)

Définit un DataFrame qui stocke la valeur de retour. Pour le relevé à la ligne 85

for (sym,val) in cp.items():
      macd[sym],macdsignal[sym],macdhist[sym] = ta.MACD(cp[sym])

Prenez le macd, macdsignal, macdhist de chaque marque.

Les lignes 90 et 91 déterminent la croix dorée et la croix morte de la ligne MACD et de la ligne de signal MACD.

macd_golden = (macd > macdsignal) & (macd.shift(1) < macdsignal.shift(1))
macd_dead = (macd < macdsignal) & (macd.shift(1) > macdsignal.shift(1))

Déterminer les signaux d'achat et de vente de MACD et RSI

buy_sig = macd_golden | (rsi < 30) #Croix d'or et survendu
sell_sig = macd_dead | (rsi > 70) #Croix morte et surachat

De cette manière, talib facilite la mise en œuvre d'indicateurs techniques bien connus tels que MACD et RSI.

Résumé

Cette fois, j'ai choisi les méthodes fréquemment utilisées pour créer des algos pour talib et pandas. J'espère que vous lirez ceci et que vous aurez une meilleure compréhension des algorithmes de QuantX Factory. Merci d'avoir lu le pauvre texte jusqu'à la fin.

Clause de non-responsabilité Précautions

Veuillez noter que nous ne sommes pas responsables des profits ou des pertes causés par des transactions réelles utilisant ce code / cette connaissance.

Recommended Posts