My name is Maskawa (https://www.facebook.com/ryozodesert) and I am an intern at SmartTrade Co., Ltd.. .. I'm studying machine learning.
Smart Trade Ltd.
Financial democratization
Based on this philosophy, we have developed a platform "QuantX Factory" that allows anyone to easily develop trading algorithms.
--No need to build an environment that tends to frustrate beginners --Various data such as closing price, high price, and trading volume of each brand are prepared, No need to prepare data set </ font> --The developed trading algorithm can be sold at the QuantX Store if it passes the examination. --For advanced users, there is also a development environment such as QuantX Lab (Source: Official Document)
In my first month as an intern, I will explain how to use the pandas and talib methods that are frequently used in creating algorithms to implement basic technical indicators such as MACD, moving averages, and RSI.
(Note: You don't have to fully understand the contents of this code right now) </ font>
#Library import
#Required library
#Import backtest engine "maron"
import maron
import maron.signalfunc as sf
import maron.execfunc as ef
#Additional library
#If you need additional libraries, add them according to the example below.
#Import the data analysis tool "pandas" and use it under the name "pd"
import pandas as pd
#Import the financial function set "talib" and use it with the name "ta"
import talib as ta
import numpy as np
#Import "" and use it as ""
# import as
#Order method(Please uncomment only one of the following three according to the desired ordering method)
# ot = maron.OrderType.MARKET_CLOSE #Order at the timing of the closing price the day after the signal is issued
ot = maron.OrderType.MARKET_OPEN #Order at the timing of the opening price the day after the signal is issued
# ot = maron.OrderType.LIMIT #Limit order
def initialize(ctx): #Initialization part
ctx.logger.debug("initialize() called") #Log output
ctx.target = 0.1
ctx.loss_cut = -0.02
ctx.plofit = 0.05
ctx.configure(
channels={
"jp.stock": {
"symbols": [
"jp.stock.2914", #JT(Japan Tobacco)
"jp.stock.8766", #Tokio Marine Holdings
"jp.stock.8031", #Mitsui
"jp.stock.8316", #Sumitomo Mitsui Financial Group
"jp.stock.8411", #Mizuho Financial Group
"jp.stock.9437", #NTT DoCoMo
"jp.stock.4502", #Takeda Pharmaceutical Company
"jp.stock.8058", #Mitsubishi Corporation
"jp.stock.9433", #KDDI
"jp.stock.9432", #Nippon Telegraph and Telephone
"jp.stock.7267", #Honda (Honda Motor Co., Ltd.)
"jp.stock.8306", #Mitsubishi UFJ Financial Group
"jp.stock.4503", #Astellas Pharma
"jp.stock.4063", #Shin-Etsu Chemical
"jp.stock.7974", #Nintendo
"jp.stock.6981", #Murata Manufacturing Co., Ltd.
"jp.stock.3382", #Seven & i Holdings
"jp.stock.9020", #East Japan Railway Company
"jp.stock.8802", #Mitsubishi Estate
"jp.stock.9022", #Central Japan Railway Company
"jp.stock.9984", #Softbank Group
"jp.stock.6861", #Keyence
"jp.stock.6501", #Hitachi
"jp.stock.6752", #Panasonic
"jp.stock.6758", #Sony
"jp.stock.6954", #FANUC
"jp.stock.7203", #Toyota Motor
"jp.stock.7751", #Canon
"jp.stock.4452", #Kao
"jp.stock.6098", #Recruit Holdings
],
#⑥
"columns": ["close_price_adj", #closing price(After stock split adjustment)
]}})
def _my_signal(data): #Trading signal generation part
#If you want to check the contents of data, please uncomment the following
# ctx.logger.debug(data)
syms = data.minor_axis #Creating a stock list
dates = data.major_axis #Creating a date list
'''↓ Write the code to get the data required for logic calculation from the 3D structure data ↓'''
cp = data["close_price_adj"].fillna("ffill")
'''↑ Write the code to get the data required for logic calculation from the 3D structure data ↑'''
'''↓ Write the code to calculate the logic required to define the trading conditions ↓'''
movave5 = cp.rolling(window = 5, center = False).mean()
movave25 = cp.rolling(window = 25, center = False).mean()
'''↑ Write the code to calculate the logic required to define the trading conditions ↑'''
#Define trading signals(Returns as a bool value)
buy_sig = (movave5 > movave25) & (movave5.shift(1) < movave25.shift(1))
sell_sig = (movave5 < movave25) & (movave5.shift(1) > movave25.shift(1))
# market_All 0 called sig.Create a data frame of "horizontal: brand name, vertical: date" that stores 0
market_sig = pd.DataFrame(data=0.0, columns=syms, index=dates)
# buy_1 when sig is True.0、sell_When sig is True-1.0, 0 when both are True.Set to 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_If you want to check the contents of sig, please uncomment the following
# ctx.logger.debug(market_sig)
return {
"buy:sig":buy_sig,
"sell:sig": sell_sig,
"market:sig": market_sig,
#Please add the data you want to display in the backtest result chart below
}
ctx.regist_signal("my_signal", _my_signal) #Signal registration
def handle_signals(ctx, date, current): #Daily processing part
'''
current: pd.DataFrame
'''
#initialize_my_Market the signal generated by signal_Store in sig
market_sig = current["market:sig"]
done_syms = set([]) #Set type that stores stocks that have been profit-taking and loss-cutting
none_syms = set([]) # portfolio.Set type that stores stocks that do not exist in positions
# portfolio.positions(Brands you own)Target stocks(sym)Check if there is
for (sym, val) in market_sig.items():
if sym not in ctx.portfolio.positions:
none_syms.add(sym)
# portfolio.positions(Brands you own)Each brand of(sym)Check if the number of shares held by
for (sym, val) in ctx.portfolio.positions.items():
if val["amount"] == 0:
none_syms.add(sym)
#Loss cut, profit taking(Profitability)settings of
#Iterative process to check the stocks you own one by one
for (sym, val) in ctx.portfolio.positions.items():
#Acquisition of profit / loss ratio
returns = val["returns"]
if returns < -0.03: #Profit and loss ratio-3%Less than(Absolute value 3%Greater loss)in the case of
#Sell order for loss cut
sec = ctx.getSecurity(sym)
sec.order(-val["amount"], comment="Loss cut(%f)" % returns)
#Added the issue assigned to sym to the set type that stores the issue for which profit settlement and loss cut have been performed.
done_syms.add(sym)
elif returns > 0.05: #Profit and loss ratio+5%If greater than
#Profit taking(Profitability)Sell order for
sec = ctx.getSecurity(sym)
sec.order(-val["amount"], comment="Profit-taking sale(%f)" % returns)
#Added the issue assigned to sym to the set type that stores the issue for which profit settlement and loss cut have been performed.
done_syms.add(sym)
buy = market_sig[market_sig > 0.0] #Buy signal
for (sym, val) in buy.items(): #Process stocks with buy signals one by one
# done_syms or none_If syms has sym
if sym in done_syms:
continue #Skip processing
#Buy order
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * 1, orderType=ot, comment="SIGNAL BUY")
#If you want to output the buy order log below, please uncomment the following(Long-term caution)
#ctx.logger.debug("BUY: %s, %f" % (sec.code(), val))
sell = market_sig[market_sig < 0.0] #Sell signal
for (sym, val) in sell.items(): #Process stocks with sell signals one by one
# done_syms or none_If syms has sym
if (sym in done_syms) | (sym in none_syms):
continue #Skip processing
#Sell order
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * -1,orderType=ot, comment="SIGNAL SELL")
Figure 1: Algorithm using golden cross and dead cross of moving average (see: https://factory.quantx.io/developer/149d79a8cf744f059af0e96918913a9f/coding / coding))
pd.DataFrame.rolling(window)
--A method used to apply window functions to pandas basic data structures such as DataFrame and Series, which returns a rolling object. --The main argument used is window, which sets the number of windows. --Window function: Function that becomes 0 except for a certain finite interval </ font>. -* When a window function is multiplied by a certain function or signal (data), the outside of the interval becomes 0, and only the inside of the finite interval remains, which facilitates numerical analysis. * (Reference: Weblio "What is a window function?") --Usage: Technical indicators such as Moving Average, Volume Moving Average Used when implementing.
Example: Implement a 25-day moving average
In line 82 of FIG.
movave25 = cp.rolling(window = 25).mean()
It says, but this is what defines the 25-day moving average.
cp.rolling (window = 25)
to cp
, which is a DataFrame that stores the closing price of each date of each brand, and a rolling object is returned.You now have move25, a DataFrame that stores 25 days' worth of moving averages.
pandas.DataFrame.shift(periods)
--Returns a DataFrame object, a method that moves (shifts) the data stored in a data frame by periods </ font> --Usage: Detects changes in the magnitude relationship between the two moving averages, the short-term line and the long-term line, from the previous day.
Example: Judgment of golden cross and dead cross
In line 87 of FIG.
buy_sig = (movave5 > movave25) & (movave5.shift(1) < movave25.shift(1))
However, this code indicates that "the 5-day moving average of the day is larger than the 25-day moving average, and the 5-day moving average of the previous day is smaller than the 25-day moving average", that is, a golden cross. I am. Line 88 is the opposite.
The shift method is used in this way.
A library that allows you to easily implement technical indicators. Please refer to the following URL for the indicators that can be implemented. https://mrjbq7.github.io/ta-lib/funcs.html
# Sample Algorithm
#Library import
#Required library
import maron
import maron.signalfunc as sf
import maron.execfunc as ef
#Additional library
#Please see the notes on the right screen for the libraries that can be used ①
import pandas as pd
import talib as ta
import numpy as np
#Order method(Please uncomment only one of the following two according to the desired ordering method)
#Please see the note on the right screen for the ordering method ②
#ot = maron.OrderType.MARKET_CLOSE #Order at the timing of the closing price the day after the signal is issued
ot = maron.OrderType.MARKET_OPEN #Order at the timing of the opening price the day after the signal is issued
#ot = maron.OrderType.LIMIT #Limit order
#Acquisition of stocks and columns
#Please see the note on the right screen for the designation of the brand ③
#Please see the note on the right screen for getting columns ④
def initialize(ctx):
#Setting
ctx.logger.debug("initialize() called")
ctx.configure(
channels={ #Channel used
"jp.stock": {
"symbols": [
"jp.stock.2914", #JT(Japan Tobacco)
"jp.stock.8766", #Tokio Marine Holdings
"jp.stock.8031", #Mitsui
"jp.stock.8316", #Sumitomo Mitsui Financial Group
"jp.stock.8411", #Mizuho Financial Group
"jp.stock.9437", #NTT DoCoMo
"jp.stock.4502", #Takeda Pharmaceutical Company
"jp.stock.8058", #Mitsubishi Corporation
"jp.stock.9433", #KDDI
"jp.stock.9432", #Nippon Telegraph and Telephone
"jp.stock.7267", #Honda (Honda Motor Co., Ltd.)
"jp.stock.8306", #Mitsubishi UFJ Financial Group
"jp.stock.4503", #Astellas Pharma
"jp.stock.4063", #Shin-Etsu Chemical
"jp.stock.7974", #Nintendo
"jp.stock.6981", #Murata Manufacturing Co., Ltd.
"jp.stock.3382", #Seven & i Holdings
"jp.stock.9020", #East Japan Railway Company
"jp.stock.8802", #Mitsubishi Estate
"jp.stock.9022", #Central Japan Railway Company
"jp.stock.9984", #Softbank Group
"jp.stock.6861", #Keyence
"jp.stock.6501", #Hitachi
"jp.stock.6752", #Panasonic
"jp.stock.6758", #Sony
"jp.stock.6954", #FANUC
"jp.stock.7203", #Toyota Motor
"jp.stock.7751", #Canon
"jp.stock.4452", #Kao
"jp.stock.6098", #Recruit Holdings
],
"columns": [
"close_price", #closing price
"close_price_adj", #closing price(After stock split adjustment)
#"volume_adj", #Volume
#"txn_volume", #Trading price
]
}
}
)
#Signal definition
def _my_signal(data):
#Get closing price data
cp=data["close_price_adj"].fillna(method="ffill")
syms = data.minor_axis #Creating a stock list
dates = data.major_axis #Creating a date list
#Where to store the data
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-Calculation of MACD by 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))
#Trading signal generation part
buy_sig = macd_golden | (rsi < 30)
sell_sig = macd_dead | (rsi > 70)
#market_Create a data frame called sig that contains all 0s
market_sig = pd.DataFrame(data=0.0, columns=syms, index=dates)
#buy_1 when sig is True.0、sell_When sig is True-1.Set to 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,
}
#Signal registration
ctx.regist_signal("my_signal", _my_signal)
def handle_signals(ctx, date, current): #Daily processing part
'''
current: pd.DataFrame
'''
#initialize_my_Market the signal generated by signal_Store in sig
market_sig = current["market:sig"]
done_syms = set([]) #Set type that stores stocks that have been profit-taking and loss-cutting
none_syms = set([]) # portfolio.Set type that stores stocks that do not exist in positions
# portfolio.positions(Brands you own)Target stocks(sym)Check if there is
for (sym, val) in market_sig.items():
if sym not in ctx.portfolio.positions:
none_syms.add(sym)
# portfolio.positions(Brands you own)Each brand of(sym)Check if the number of shares held by
for (sym, val) in ctx.portfolio.positions.items():
if val["amount"] == 0:
none_syms.add(sym)
#Loss cut, profit taking(Profitability)settings of
#Iterative process to check the stocks you own one by one
for (sym, val) in ctx.portfolio.positions.items():
#Acquisition of profit / loss ratio
returns = val["returns"]
if returns < -0.03: #Profit and loss ratio-3%Less than(Absolute value 3%Greater loss)in the case of
#Sell order for loss cut
sec = ctx.getSecurity(sym)
sec.order(-val["amount"], comment="Loss cut(%f)" % returns)
#Added the issue assigned to sym to the set type that stores the issue for which profit settlement and loss cut have been performed.
done_syms.add(sym)
elif returns > 0.05: #Profit and loss ratio+5%If greater than
#Profit taking(Profitability)Sell order for
sec = ctx.getSecurity(sym)
sec.order(-val["amount"], comment="Profit-taking sale(%f)" % returns)
#Added the issue assigned to sym to the set type that stores the issue for which profit settlement and loss cut have been performed.
done_syms.add(sym)
buy = market_sig[market_sig > 0.0] #Buy signal
for (sym, val) in buy.items(): #Process stocks with buy signals one by one
# done_syms or none_If syms has sym
if sym in done_syms:
continue #Skip processing
#Buy order
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * 1, orderType=ot, comment="SIGNAL BUY")
#If you want to output the buy order log below, please uncomment the following(Long-term caution)
#ctx.logger.debug("BUY: %s, %f" % (sec.code(), val))
sell = market_sig[market_sig < 0.0] #Sell signal
for (sym, val) in sell.items(): #Process stocks with sell signals one by one
# done_syms or none_If syms has sym
if (sym in done_syms) | (sym in none_syms):
continue #Skip processing
#Sell order
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * -1,orderType=ot, comment="SIGNAL SELL")
Figure 2: Algorithm using RSI and MACD golden cross and dead cross (see: https://factory.quantx.io/developer/6ba1eb1b748d46a18ce128fea3156282/coding / coding))
RSI
talib.RSI(close, timeperiod = 14)
――RSI is a technical index that distinguishes between “overbought” and “oversold”. --It takes np.double type np.arrays object close indicating the closing price and timeperiod indicating the period as arguments.
Example: At line 82 of the code in Figure 2.
rsi = pd.DataFrame(data = 0.0, columns = syms, index = dates)
Define a DataFrame to store the RSI of each issue
For statement on line 85
for (sym,val) in cp.items():
rsi[sym] = ta.RSI(cp[sym].values.astype(np.double), timeperiod = 10)
The RSI of each brand is stored in.
--Since cp [sym]
is a DataFrame type object, convert it to an array type object with cp [sym] .values
.
--And cp [sym] .values.astype (np.double)
converts the contents of the array to np.double type.
--This time, we will take RSI for 10 days, so set timeperiod = 10.
――Judge buying and selling by referring to whether it is "oversold" or "overbought"
MACD
ta.MACD(close)
――It is a technical index that applies the moving average line, and measures the timing of buying and selling by combining the MACD line and the Japanese line of the MACD signal line. --Take a Series object close that stores the closing price of the issue as an argument. --Returns three DataFrame type objects
Example: In the code lines 79 to 81 of Fig. 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)
Define a DataFrame to store the return value. For statement on line 85
for (sym,val) in cp.items():
macd[sym],macdsignal[sym],macdhist[sym] = ta.MACD(cp[sym])
Take the macd, macdsignal, macdhist of each brand in.
Lines 90 and 91 determine the golden cross and dead cross of the MACD line and MACD signal line.
macd_golden = (macd > macdsignal) & (macd.shift(1) < macdsignal.shift(1))
macd_dead = (macd < macdsignal) & (macd.shift(1) > macdsignal.shift(1))
buy_sig = macd_golden | (rsi < 30) #Golden cross and oversold
sell_sig = macd_dead | (rsi > 70) #Dead cross and overbought
In this way, talib makes it easy to implement well-known technical indicators such as MACD and RSI.
This time, I picked up the methods that are frequently used in creating algos for talib and pandas. I hope you read this and get a better understanding of QuantX Factory's algorithms. Thank you for reading the poor text until the end.
Please note that we are not responsible for any profit or loss caused by actual transactions using this code / knowledge.