This time, I tried to build an algorithm for the breakout method at Quantx Factory provided by Smart Trade Ltd.
This is Qiita's first post. Originally from Kochi prefecture, I attend a university in Yokohama. My major is physics, programming is a little used in university experiments, and I am a complete beginner in Python (sweat) I just started an internship at Smart Trade the other day, so I would like to update what I have learned as an output.
Breakout is to break through the points ** that many market participants are aware of, such as resistance lines, support lines, and highest prices.
Basically, after the breakout, there is a market habit of going to a higher price (cheaper).
In a strong market, you can make a profit without delay. (Strong against trends)
When you fail to break (deceive) because you take a position in the high price range, the loss cut tends to be large.
After breaking the high price of the last 10 days, we will pick up the place where we pushed 50% or more against the price range of the 10 days. In addition, in order to avoid deception, the strength of the trend is judged using the technical index ADX. (For the closing price, the value adjusted for the stock split is used.)
Settlement at the point where the latest low price was updated In addition, for fund management, we also settle according to the rate of increase and decrease.
Copy ↑ Please share.
import maron
import pandas as pd
import numpy as np
import talib as ta
ot = maron.OrderType.MARKET_OPEN #Order at the timing of the opening price the day after the signal is issued
def initialize(ctx):
#Setting
ctx.logger.debug("initialize() called")
#How many days in the past to observe
ctx.high_term = 10
ctx.low_term = 10
ctx.vol_term = 10
#What percentage do you have for your position
ctx.target = 0.5
ctx.configure(
channels={ #Channel used
"jp.stock": {
"symbols": [
"jp.stock.7203",
"jp.stock.9984",
"jp.stock.8306",
"jp.stock.4502",
"jp.stock.6758",
"jp.stock.6861",
"jp.stock.9432",
"jp.stock.8316",
"jp.stock.7267",
"jp.stock.8411",
"jp.stock.6098",
"jp.stock.7974",
"jp.stock.9433",
"jp.stock.9022",
"jp.stock.8058",
"jp.stock.4452",
"jp.stock.8766",
"jp.stock.6954",
"jp.stock.6981",
"jp.stock.9020",
"jp.stock.4063",
"jp.stock.7751",
"jp.stock.6501",
"jp.stock.3382",
"jp.stock.9437",
"jp.stock.8031",
"jp.stock.4503",
"jp.stock.8802",
"jp.stock.6752",
],
"columns": [
"high_price_adj",
"low_price_adj",
"close_price_adj"
"volume_adj",
]}})
def _BREAK_NEW_HIGH(data):
#Fill in missing values
hp = data["high_price_adj"].fillna(method="ffill")
lp = data["low_price_adj"].fillna(method="ffill")
cp = data["close_price_adj"].fillna(method="ffill")
vol = data["volume_adj"].fillna(method="ffill")
#Get the highest price in the last 10 days
new_max = hp.rolling(window=ctx.high_term, center=False).max()
new_min = lp.rolling(window=ctx.low_term, center=False).min()
vol_max = vol.rolling(window=ctx.vol_term, center=False).max()
#Authenticity of whether the highest price is the same as today's high price
today_is_new_high = new_max == hp
today_is_new_low = new_min == lp
today_is_vol_max = vol_max == vol
price_range = new_max - new_min #price range
ADX = pd.DataFrame(data=0,columns=cp.columns, index=cp.index)
for (sym,val) in cp.items():
ADX[sym] = ta.ADX(hp[sym], lp[sym], cp[sym], timeperiod=14)
buy_sig1 = (new_max - lp) > price_range*0.5
buy_sig2 = ADX > 32
buy_sig = (buy_sig1) & (buy_sig2)
sell_sig = lp < new_min
# market_Create a data frame called sig that contains all 0s
market_sig = pd.DataFrame(data=0.0, columns=hp.columns, index=hp.index)
# 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
return {
"ADX":ADX,
"New High":new_max,
"New Low":new_min,
"price range":price_range,
"market:sig": market_sig,
}
#Signal registration
ctx.regist_signal("BREAK_NEW_HIGH", _BREAK_NEW_HIGH)
def handle_signals(ctx, date, current):
market_sig = current["market:sig"]
done_syms = set([])
#Loss cut, profit setting
for (sym, val) in ctx.portfolio.positions.items():
returns = val["returns"]
if returns < -0.025:
sec = ctx.getSecurity(sym)
sec.order(-val["amount"], comment="Loss cut(%f)" % returns)
done_syms.add(sym)
elif returns > 0.07:
sec = ctx.getSecurity(sym)
sec.order(-val["amount"], comment="Profit-taking sale(%f)" % returns)
done_syms.add(sym)
#Buy signal
buy = market_sig[market_sig > 0.0]
for (sym, val) in buy.items():
if sym in done_syms:
continue
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * 1.5,orderType=ot, comment="SIGNAL BUY")
# ctx.logger.debug("BUY: %s, %f" % (sec.code(), val))
pass
#Sell signal
sell = market_sig[market_sig < 0.0]
for (sym, val) in sell.items():
if sym in done_syms:
continue
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * -1.5,orderType=ot, comment="SIGNAL SELL")
#ctx.logger.debug("SELL: %s, %f" % (sec.code(), val))
pass
I backtested the market price for the past 3 years.
P & L: 77.71% Maximum drawdown: 10.1% Sharpe ratio: 1.682 Volatility: 0.123 α : 0.162 β : 0.525
The result itself is not bad, but the number of transactions was much higher than I had expected. Probably because there is a lot of pyramiting (additional purchase). (Maybe you can trade a little less often)
As an improvement point, ・ Suppress DD a little more ・ Scrutiny of entry points ・ Implementation of portfolio management ・ It does not depend much on the brand
Is that the place ...
If it can be improved, I will correct it as appropriate. (Article writing date 2020/2/17)
・ What is Sharpe ratio ・ Maximum DD ・ Volatility [Look at the algorithm index like this! ] https://blog.quantx.io/2019/03/25/yenzo-algo-erabikata/
・ New high price update algorithm #QuantX https://qiita.com/shinseitaro/items/a098d99f15e99ac3e0c3
Please note that we are not responsible for any profit or loss incurred in actual transactions using this code or knowledge.
Recommended Posts