【Application】TQuant Lab Ichimoku Kinko Hyo Strategy, A Self-contained Technical Analysis Indicator

TEJ 台灣經濟新報
TEJ-API Financial Data Analysis
10 min readMay 8, 2024
Ichimoku Kinko Hyo
Photo by Manuel Cosentino on Unsplash

Highlight

  • Difficulty:★★★☆☆
  • Introduction to Ichimoku Kinko Hyo and trailing stop.
  • Write an Ichimoku Kinko Hyo strategy using TQuant Lab backtesting platform and backtest risk and performance.

Introduction

Ichimoku Kinko Hyo (also known as Cloud Charts, いちもくきんこうひょう) was invented by Japanese journalist Goichi Hosoda, but it was not publicly disclosed at the time. Forty years later, between 1975 and 6 years after that, Goichi Hosoda, using the pseudonym Ichimoku Sanjin, published seven series of works under the name “Ichimoku Kinko Hyo,” explaining in detail this indicator and the philosophical thinking behind its trading system.

Unlike traditional concepts such as stock prices influenced by price-volume relationships, supply and demand for buying and selling, and fundamental aspects of companies, Ichimoku Kinko Hyo believes that time is an essential factor affecting price changes, especially under the influence of time, prices have cyclical changes. There is always a market concern that stocks will fall after rising for a long time and rise after falling for a long time. The overall market sentiment reflects a regularity of fluctuations in market behavior under the influence of time, which forms the basis of the “Time Theory” of Ichimoku Kinko Hyo.

In addition, Ichimoku Kinko Hyo is a philosophical, technical analysis indicator. Rather than being an indicator per se, the author believes it should be regarded as Goichi Hosoda’s analysis and reflection on the market and society. The thought behind it is worth exploring in depth. Due to space constraints, this article does not elaborate on this. The author believes that the theory of Ichimoku Kinko Hyo and market equilibrium has good insights into Ichimoku Kinko Hyo. Those interested can refer to it.

Introduction to Ichimoku Kinko Hyo Framework

Time Theory

The time theory of Ichimoku Kinko Hyo is a method of analyzing time and market turning points. “9, 17, 26” are the basic numbers and can be used to examine whether the market will likely have a turning point during this period, which is a significant value.

Interpretation Method

  • Conversion Line (tenkan_sen): The turning line (also known as the reversal line) is the average of the highest and lowest prices in the past nine days. If the turning line rises, it is judged that the upward momentum is strong, and if it falls, it is considered that the downward trend is strong. Because it is calculated based on a short period of nine days, it is used to analyze short-term trends.
  • Base Line (kijun_sen): The standard line is the average of the highest and lowest prices over the past 26 days. If the standard line rises, it is judged that the upward momentum is strong, and if it falls, it is considered that the downward trend is strong. Since it is calculated based on a period of 26 days, it is used to analyze medium-term trends.
  • Leading Span A / B (senkou_span_a/b): Leading Span A predicts the future trend for the next 26 days based on the average turning line and the standard line. Leading Span B is a line that predicts the trend for the next 26 days based on the average of the highest and lowest prices of the past 52 days. Since both show the average trend for the next 26 days, they help analyze future price changes. After shading between Leading Span A and Leading Span B, the “cloud region or cloud band” is called the part with A < B, green, and the part with A > B, red.
  • Lagging Span (chikou_span): The lagging span is the stock price 26 days ago. If it is above the price line, it indicates a strong upward trend in the market; if it is below the price line, it indicates a solid downward trend.

Turning Lines and Standard Lines

Ichimoku Kinko Hyo also has a method called “Three-Line Confirmation” and “Three-Line Reversal” for interpreting. “Three-line confirmation” represents a buy signal, and “Three-Line Reversal” represents a sell signal. Usually, if the three-line confirmation is met outside the stock’s price range, there will be a stronger upward trend, and vice versa. This article will fine-tune the buy signal based on the three-line confirmation.

Conditions for Three-Line Confirmation:

  • The Conversion Line exceeds the Base Line.
  • The Lagging Span is above the price.
  • The price exceeds the cloud area.

Conditions for Three-Line Reversal:

  • The Conversion Line is below the Base Line.
  • The Lagging Span is below the price.
  • The price is below the cloud area.

Editing Environment and Module Requirements

This article uses MacOS and Jupyter Notebook as the editor.

Data Import and Use of get_universe Function to Obtain Stock Pool

This strategy first fetches all stock codes of common stocks, including both listed and over-the-counter (OTC) markets, for one year, from April 1, 2018, to March 31, 2019.

import os
import tejapi
import pandas as pd
import numpy as np

os.environ['TEJAPI_KEY'] = "your key"
os.environ['TEJAPI_BASE'] = "https://api.tej.com.tw"
start = '2018-04-01'
end = '2019-03-31'
from zipline.sources.TEJ_Api_Data import get_universe
pool = get_universe(start, end, mkt = ['TWSE', 'OTC'], stktp_e=['Common Stock-Foreign', 'Common Stock'])
len(pool)

Using TEJToolAPI to Fetch MSCI Component Stocks

The Ichimoku Kinko Hyo strategy selects MSCI component stocks from the above stock codes using the TEJToolAPI.

average_vol = df.groupby('股票代碼')['成交量_千股'].mean().reset_index()
average_vol = average_vol.rename(columns={'成交量_千股': '平均成交量'})
high_price_stocks = df.groupby('股票代碼')['最低價'].min().reset_index()
high_price_stocks = high_price_stocks[high_price_stocks['最低價'] >= 50]
merge_data = pd.merge(average_vol, high_price_stocks, on='股票代碼', how='inner')
top_100_vol = merge_data.sort_values(by='平均成交量', ascending=False).head(100)
top_100_vol
Ichimoku Kinko Hyo

Loading data into bundle

To avoid lookahead bias, this strategy’s five-year backtesting period is from April 1, 2019, to April 1, 2024. It includes the aforementioned 91 constituent stocks, along with the Taiwan Weighted Index (IR0001), as a benchmark for market comparison.

Below is the list of the 91 constituent stocks and the Taiwan Weighted Index:

!zipline ingest -b tquant
!zipline bundle-info
Ichimoku Kinko Hyo
Component stock and backtest period

Creating Pipeline Function

Creating Custom Factor

CustomFactor allows users to design custom factors as needed. In this case, we will use it to handle:

Average True Range (ATR): Used to calculate trailing stop levels. Pipeline allows users to process quantitative indicators and price-volume data for multiple assets quickly. In this case, we will use it to handle:

Conversion Line (tenkan_sen) Base Line (kijun_sen) Leading Span A / B (senkou_span_a/b) Cloud area or cloud band (cloud_red) Lagging Span (chikou_span)

from zipline.pipeline import Pipeline
from zipline.TQresearch.tej_pipeline import run_pipeline
def make_pipeline():

Ich = IchimokuKinkoHyo(
inputs = [TWEquityPricing.high, TWEquityPricing.low, TWEquityPricing.close],
window_length = 52,
)
atr = AverageTrueRange(inputs = [TWEquityPricing.high, TWEquityPricing.low, TWEquityPricing.close],
window_length = 52,
)

return Pipeline(
columns = {
'curr_price': TWEquityPricing.close.latest,
"tenkan_sen": Ich.tenkan_sen,
"kijun_sen": Ich.kijun_sen,
"senkou_span_a": Ich.senkou_span_a,
"senkou_span_b": Ich.senkou_span_b,
'cloud_red': Ich.senkou_span_a < Ich.senkou_span_b,
"chikou_span": Ich.chikou_span,
'stop_loss': atr.ATR,
},
# screen = ~StaticAssets([benchmark_asset])
screen = ~StaticAssets([benchmark_asset]) & (Ich.senkou_span_a > 0) & (Ich.senkou_span_b > 0)
)
my_pipeline = run_pipeline(make_pipeline(), start_dt, end_dt)
my_pipeline
Ichimoku Kinko Hyo
Pipeline partial data

Creating Initialize Function

The initialize() function defines the daily trading environment before trading begins. In this example, we set:

  • Slippage costs
  • Transaction costs model for the Taiwan stock market
  • Weighted return index (IR0001) as the benchmark
  • Incorporating the Ichimoku Kinko Hyo indicators designed in Pipeline into the trading process
  • Setting the context.stop_loss variable to record stop-loss points during backtesting
  • Setting the context.holding variable to record whether a position in a particular stock is held
  • Setting the context.trailing_stop variable to record whether the trailing stop is being applied
  • Setting the context.last_buy_price variable to record the last purchase price
  • Setting the context.trailing_count variable to record the number of trailing stop instances
  • Setting the context.buy_count variable to limit the maximum number of trades per stock
from zipline.finance import slippage, commission
from zipline.api import *

def initialize(context):
set_slippage(slippage.VolumeShareSlippage())
set_commission(commission.Custom_TW_Commission(min_trade_cost = 20, discount = 1.0, tax = 0.003))
attach_pipeline(make_pipeline(), 'mystrats')
set_benchmark(symbol('IR0001'))
context.stop_loss = {}
context.trailing_stop = {}
context.last_buy_price = {}
context.trailing_count = {}
context.holding = {}
context.buy_count = {}

Creating Handle_data Function

The handle_data() function is important for constructing the Ichimoku Kinko Hyo strategy. It is called every day after the start of backtesting, and its main tasks include setting trading strategies, placing orders, and recording trading information.

Note: To avoid the possibility of erroneous entry signals by the Ichimoku Kinko Hyo during periods of price consolidation, this article uses an additional *1.01 condition on tenkan_sen > kijun_sen. This is done in the hope of entering the market only when the upward trend is sufficiently explicit, thereby achieving a certain degree of avoidance of consolidation periods.

For detailed trading rules regarding this strategy, please refer to Ichimoku Kinko Hyo.ipynb

        # 三役好轉 (tenkan_sen > kijun_sen*1.015 : avoid the Darvas Box Theory)
if (curr_price > senkou_span_b) and (cloud_red == True) and (tenkan_sen > kijun_sen*1.01) and (context.buy_count[f'{i}'] <= 5):
order_percent(i, 0.01)
buy = True
context.stop_loss[f'{i}'] = curr_price - (1.25 * stop_loss)
context.last_buy_price[f'{i}'] = curr_price
record(
**{
f'buy_{sym}':buy
}
)
context.holding[f'{i}'] = True
context.buy_count[f'{i}'] += 1

# reset stop loss point
if (curr_price >= (1.3**context.trailing_count[f'{i}'])*context.last_buy_price[f'{i}']) and (context.holding[f'{i}'] == True) and (context.trailing_stop[f'{i}'] == False):
context.stop_loss[f'{i}'] = 1.3*context.stop_loss[f'{i}']
context.trailing_stop[f'{i}'] = True
context.trailing_count[f'{i}'] += 1
elif (curr_price >= (1.3**context.trailing_count[f'{i}'])*context.last_buy_price[f'{i}']) and (context.holding[f'{i}'] == True) and (context.trailing_stop[f'{i}'] == True):
context.stop_loss[f'{i}'] = 1.3*context.stop_loss[f'{i}']
context.trailing_count[f'{i}'] += 1

if (curr_price <= context.stop_loss[f'{i}']) and (context.holding[f'{i}'] == True):
order_target(i, 0)
sell = True
context.stop_loss[f'{i}'] = None
context.trailing_stop[f'{i}'] = None
context.trailing_count[f'{i}'] = None
record(
**{
f'sell_{sym}':sell
}
)
context.holding[f'{i}'] = None
context.buy_count[f'{i}'] = None

Executing Trading Strategy

Use the run_algorithm() function to execute the Ichimoku Kinko Hyo strategy as defined above. Set the trading period from start_dt (2019-04-01) to end_dt (2024-04-01), using the dataset tquant, with an initial capital of 20 million dollars. The output results represent the daily performance and trade details.

import matplotlib.pyplot as plt
from zipline import run_algorithm
results = run_algorithm(
start = start_dt,
end = end_dt,
initialize = initialize,
bundle = 'tquant',
analyze = analyze,
capital_base = 2e7,
handle_data = handle_data
)
results
Ichimoku Kinko Hyo
Return and entry/exit performance changes based on the Ichimoku Kinko Hyo strategy for individual stocks (red marks indicate buy signals, green marks indicate sell signals).
Ichimoku Kinko Hyo
Backtest Details

Evaluating performance using Pyfolio

import pyfolio as pf 
returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(results)
benchmark_rets = results['benchmark_return']
pf.tears.create_full_tear_sheet(returns=returns,
positions=positions,
transactions=transactions,
benchmark_rets=benchmark_rets
)
Backtest Performance & Benchmark Comparison Chart

We can observe that the Ichimoku Kinko Hyo strategy has provided excellent performance over the 58 months, with an annualized return of 23.554% and a cumulative return of 178.194%. The profit performance is quite impressive. The Sharpe ratio 1.38 indicates a relatively high return compared to the risk. Additionally, the β value of 0.66 suggests that the strategy’s volatility is relatively insensitive to overall market volatility, reflecting the core concept of the Ichimoku Kinko Hyo system in detaching from the market.

Regarding maximum drawdown, we can see a significant downturn during the systemic risk increase due to the epidemic between the 22nd and 23rd years. Stable growth trends have characterized other periods. Utilizing the entry signals provided by the Ichimoku Kinko Hyo, along with a strategy incorporating ATR trailing stops, is a robust approach for achieving consistent returns surpassing the market over the long term.

Ichimoku Kinko Hyo
Monthly Returns Variation Chart
Ichimoku Kinko Hyo
Portfolio Holdings Variation Chart (Top Ten)

It can be seen that the holding period for each stock is quite consistent, with little bias towards any particular stock.

Viewing the performance of a specific stock under the Ichimoku Kinko Hyo strategy

graph(2330, True)

Since this strategy involves backtesting on a selection of stocks rather than individual stock backtesting, it’s impossible to quickly ascertain each stock's actual entry and exit points within the Ichimoku Kinko Hyo system. Therefore, I have additionally written a function to facilitate the examination of individual stock trading situations. For more details, please refer to the source code on GitHub.

Ichimoku Kinko Hyo
The individual Ichimoku Kinko Hyo entry and exit performance for each stock (Red marks indicate buy signals, while green marks indicate sell signals)

A notable point is that the entry method based on Ichimoku Kinko Hyo’s three signals does not include exit criteria. In practical testing, exiting based on the reversal of the three signals would result in losing many profitable trends. Therefore, this strategy employs a trailing stop-loss method for exits. For instance, in the chart above, you can see that the strategy had a sell order triggered by a stop-loss signal on TSMC (2330) at the beginning of 2021, capturing a trend lasting over half a year. However, apart from trailing stop-loss, one could incorporate profit-taking mechanisms such as setting profit targets or other means of securing gains. Additionally, strategies involving both long and short positions could be explored.

Conclusion

This strategy uses the Ichimoku Kinko Hyo for backtesting simulations, leveraging its signals of three conversions for entry and complementing it with trailing stop-loss for profit-taking, yielding promising backtest results. Investors are welcome to consider this approach.

In the future, I will continue to introduce various indicators constructed using the TEJ database and backtest their performance. Therefore, readers interested in trading backtests are encouraged to explore TQuant Lab‘s related solutions, utilizing high-quality databases to build their trading strategies.

A friendly reminder: This strategy is for reference only and does not constitute any recommendation for commodities or investments.

Source Code

Click Here to Github

Extended Reading

About

--

--

TEJ 台灣經濟新報
TEJ-API Financial Data Analysis

TEJ 為台灣本土第一大財經資訊公司,成立於 1990 年,提供金融市場基本分析所需資訊,以及信用風險、法遵科技、資產評價、量化分析及 ESG 等解決方案及顧問服務。鑒於財務金融領域日趨多元與複雜,TEJ 結合實務與學術界的精英人才,致力於開發機器學習、人工智慧 AI 及自然語言處理 NLP 等新技術,持續提供創新服務