Struggling to get started with quantitative analysis? This article will guide you step by step on building a complete automated backtesting system using stock APIs. Whether you’re monitoring real-time stock quotes or developing strategies with stock APIs and high-frequency real-time quote APIs, these tools provide robust support. As part of financial APIs and market data APIs, these interfaces cover not only index futures and U.S. stock market data but also seamless integration with the Nasdaq exchange, enabling advanced quantitative analysis like Chan Theory backtesting. In this article, we’ll use Python and the iTick API as an example to detail how to integrate stock APIs, fetch Nasdaq stock data, and apply it to Chan Theory backtesting strategies.
1. Choosing the Right API
*…
Struggling to get started with quantitative analysis? This article will guide you step by step on building a complete automated backtesting system using stock APIs. Whether you’re monitoring real-time stock quotes or developing strategies with stock APIs and high-frequency real-time quote APIs, these tools provide robust support. As part of financial APIs and market data APIs, these interfaces cover not only index futures and U.S. stock market data but also seamless integration with the Nasdaq exchange, enabling advanced quantitative analysis like Chan Theory backtesting. In this article, we’ll use Python and the iTick API as an example to detail how to integrate stock APIs, fetch Nasdaq stock data, and apply it to Chan Theory backtesting strategies.
1. Choosing the Right API
iTick: Strikes a balance between professionalism and ease of use. It focuses on providing millisecond-latency real-time data for global markets (such as U.S., European, Hong Kong, and Asia-Pacific stocks) and supports WebSocket streaming. Ideal for developers who need solid data quality while keeping costs in check. It offers a permanent free tier, which typically includes a certain amount of basic real-time and historical data calls. Premium plans unlock higher call frequencies, making it a worthwhile option for free or low-cost setups.
Polygon.io: A professional-grade choice in this space. It connects directly to exchange data sources, offering low-latency (millisecond-level) real-time quotes, pre- and post-market data, and even Level 2 depth data. Its high data quality makes it suitable for building serious trading systems. While it provides a free trial tier, its core value lies in paid services. The free tier often has strict rate and feature limits, and paid plans can be pricey—but if your budget allows, it’s an excellent pick.
Alpha Vantage: Its free version typically comes with delayed real-time data (e.g., 15 minutes). It excels in offering extensive historical data and built-in technical indicators (like SMA and RSI), making it great for backtesting and learning. Perfect for research, strategy prototyping, academic studies, and small personal projects due to its rich free historical data and integrated indicators for quick idea validation. However, when you exceed free limits or need true real-time data, you’ll need to upgrade to paid plans.
2. iTick API Overview
Before getting started, register an account on the iTick official platform and obtain your API Token. Note that all requests must include the "token" header.
Based on the provided documentation, here are the key endpoints:
- Batch Historical K-Line Query (/stock/klines): Fetches historical OHLCV data for backtesting.
- Batch Real-Time Quotes (/stock/quotes): Retrieves latest prices, percentage changes, etc.
- Batch Real-Time Order Book (/stock/depths): Gets bid/ask depth.
- Batch Real-Time Trades (/stock/ticks): Obtains tick-by-tick transaction data.
- WebSocket Real-Time Streaming: For subscribing to real-time quotes, order books, and trades.
For Nasdaq, set the region parameter to "US" and codes like "AAPL,TSLA".
3. Python Implementation: Fetching Historical Data and Chan Theory Backtesting
Step 1: Install Dependencies
Use the requests library for HTTP requests and pandas for data handling:
pip install requests pandas numpy
Step 2: Fetch Historical K-Line Data
Use the /stock/klines endpoint to query AAPL’s 5-minute K-lines (kType=2), with a limit of 1000 bars, and region=US.
import requests
import pandas as pd
# API Configuration
BASE_URL = "https://api.itick.org"
TOKEN = "your_token" # Replace with your API Token
def get_historical_klines(region, codes, ktype, limit, et=None):
url = f"{BASE_URL}/stock/klines?region={region}&codes={codes}&kType={ktype}&limit={limit}"
if et:
url += f"&et={et}"
headers = {
"accept": "application/json",
"token": TOKEN
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
data = response.json()
if data["code"] == 0:
# Extract data for AAPL as an example
klines = data["data"].get(codes.split(',')[0], [])
df = pd.DataFrame(klines)
df['t'] = pd.to_datetime(df['t'], unit='ms') # Convert timestamp to datetime
return df[['t', 'o', 'h', 'l', 'c', 'v']] # OHLCV
else:
print("API Error:", data["msg"])
else:
print("HTTP Error:", response.status_code)
return None
# Example: Fetch AAPL's latest 1000 5-minute K-lines
df_klines = get_historical_klines("US", "AAPL", 2, 1000)
if df_klines is not None:
print(df_klines.head())
Sample response (JSON format):
{
"code": 0,
"msg": null,
"data": {
"AAPL": [
{
"tu": 56119888070.5,
"c": 534.5,
"t": 1741239000000,
"v": 104799385,
"h": 536,
"l": 534.5,
"o": 535
}
]
}
}
Once converted to a DataFrame, it’s ready for further analysis.
Step 3: Implementing Chan Theory Core Elements and Backtesting
The core of Chan Theory backtesting involves identifying fractals (tops/bottoms), pens (trend segments), and pivots (consolidation zones), then generating buy/sell signals based on pivots for simulated trading. Below is a complete backtesting implementation using pandas, including fractal detection, pen detection, pivot detection, and a simple strategy (e.g., buy on pivot breakout above, sell on breakdown below).
import numpy as np
def detect_fractals(df):
df = df.copy()
df['top_fractal'] = (df['h'].shift(1) < df['h']) & (df['h'].shift(-1) < df['h'])
df['bottom_fractal'] = (df['l'].shift(1) > df['l']) & (df['l'].shift(-1) > df['l'])
return df
def detect_pens(df):
pens = []
direction = None
start_idx = None
for i in range(1, len(df) - 1):
if df.loc[i, 'top_fractal']:
if direction == 'down':
pens.append(('down', start_idx, i))
start_idx = i
direction = 'up'
elif direction is None:
start_idx = i
direction = 'up'
elif df.loc[i, 'bottom_fractal']:
if direction == 'up':
pens.append(('up', start_idx, i))
start_idx = i
direction = 'down'
elif direction is None:
start_idx = i
direction = 'down'
if start_idx is not None and direction is not None:
pens.append((direction, start_idx, len(df)-1))
return pens
def detect_pivots(pens, df):
pivots = []
for i in range(2, len(pens)):
pen1, pen2, pen3 = pens[i-2], pens[i-1], pens[i]
if pen1[0] == 'up' and pen3[0] == 'up':
low1 = df.loc[pen1[2], 'l']
high1 = df.loc[pen1[1], 'h']
low3 = df.loc[pen3[2], 'l']
high3 = df.loc[pen3[1], 'h']
low = min(low1, low3)
high = max(high1, high3)
if low > df.loc[pen2[2], 'l'] or high < df.loc[pen2[1], 'h']:
continue
overlap_low = max(low1, low3)
overlap_high = min(high1, high3)
if overlap_low < overlap_high:
pivots.append((pen1[1], pen3[2], overlap_low, overlap_high))
elif pen1[0] == 'down' and pen3[0] == 'down':
high1 = df.loc[pen1[2], 'h']
low1 = df.loc[pen1[1], 'l']
high3 = df.loc[pen3[2], 'h']
low3 = df.loc[pen3[1], 'l']
high = max(high1, high3)
low = min(low1, low3)
if high < df.loc[pen2[2], 'h'] or low > df.loc[pen2[1], 'l']:
continue
overlap_high = min(high1, high3)
overlap_low = max(low1, low3)
if overlap_low < overlap_high:
pivots.append((pen1[1], pen3[2], overlap_low, overlap_high))
return pivots
def backtest_chan(df, pivots):
signals = pd.Series(0, index=df.index)
position = 0
entry_price = 0
for start, end, low, high in pivots:
for i in range(end, len(df)):
if df.loc[i, 'c'] > high and position == 0:
signals[i] = 1 # Buy
position = 1
entry_price = df.loc[i, 'c']
elif df.loc[i, 'c'] < low and position == 1:
signals[i] = -1 # Sell
position = 0
df['signals'] = signals
df['returns'] = df['c'].pct_change()
df['strategy_returns'] = df['signals'].shift(1) * df['returns']
df['strategy_returns'] = df['strategy_returns'].fillna(0)
cumulative_returns = (1 + df['strategy_returns']).cumprod()
total_return = cumulative_returns.iloc[-1] - 1
print(f"Total Strategy Return: {total_return:.2%}")
return df, total_return
# Example Usage
if df_klines is not None:
df_klines = detect_fractals(df_klines)
pens = detect_pens(df_klines)
pivots = detect_pivots(pens, df_klines)
df_backtest, total_return = backtest_chan(df_klines, pivots)
print(df_backtest.tail()) # View backtest results
This is a simplified Chan Theory backtesting version: After detecting fractals and pens, it identifies pivots (formed by at least three overlapping pens), then buys on upside breakouts and sells on downside breakdowns from pivots. It calculates the strategy’s cumulative returns. In practice, add optimizations like stop-losses and position sizing. Note that Chan Theory is subjective, and this code serves as an example only.
Step 4: Real-Time Data Subscription (WebSocket)
For real-time Chan Theory monitoring, use WebSocket to subscribe to Nasdaq stocks.
import websocket
import json
import threading
import time
WS_URL = "wss://api.itick.org/stock"
def on_message(ws, message):
data = json.loads(message)
if data.get("data"):
market_data = data["data"]
if market_data.get("type") == "quote":
print("Real-time Quote:", market_data)
def on_open(ws):
subscribe_msg = {
"ac": "subscribe",
"params": "AAPL$US",
"types": "quote"
}
ws.send(json.dumps(subscribe_msg))
def send_ping(ws):
while True:
time.sleep(30)
ping_msg = {"ac": "ping", "params": str(int(time.time() * 1000))}
ws.send(json.dumps(ping_msg))
ws = websocket.WebSocketApp(
WS_URL,
header={"token": TOKEN},
on_open=on_open,
on_message=on_message
)
ping_thread = threading.Thread(target=send_ping, args=(ws,))
ping_thread.daemon = True
ping_thread.start()
ws.run_forever()
This will stream real-time quotes for AAPL and can be extended to order books and trades for dynamic Chan Theory analysis.
4. Conclusion
This article, based on Python, walks through the full process of integrating Nasdaq exchange data and implementing Chan Theory backtesting—from API setup and data fetching to structure identification and strategy construction. It’s important to note that this content is for technical research purposes only and does not constitute investment advice. The basic Chan Theory backtesting here doesn’t handle K-line inclusions, gaps, or other nuances; further algorithm refinements are needed for real-world applications. For high-frequency trading, prioritize API latency and data stability—enhance performance with iTick’s high-frequency quote endpoints and local caching.
Disclaimer: This article is for reference only and does not constitute investment advice. Markets involve risks; invest with caution.