In quantitative trading and technical analysis, RSI (Relative Strength Index), MACD (Moving Average Convergence Divergence), and Moving Averages (MA) are three of the most classic and widely used technical indicators. They help traders identify market trends, momentum, and potential reversal points. This article will explain in detail how to obtain high-quality financial data through common market data APIs and manually compute these core indicators in Python, laying a solid foundation for building your own quantitative strategies.
1. Data Acquisition and Indicator Calculation
1. Environment Setup and Data Retrieval
Install the required Python libraries and fetch candlestick (K-line) data.
# Install required libraries
# pip install requests pandas numpy matplotlib
import requests
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Set API request headers (common to all iTick endpoints)
headers = {
"accept": "application/json",
"token": "your_API_Token" # Replace with your actual token
}
def fetch_kline_from_itick(symbol='700.HK', region='HK', k_type=8, limit=100):
"""
Fetch historical K-line data from the iTick API
Parameters:
symbol: Ticker symbol, e.g., '700.HK' for Tencent Holdings
region: Market region, e.g., 'HK' (Hong Kong), 'US' (US), 'CN' (Mainland China)
k_type: K-line period, 1=1-minute, 2=5-minute, ..., 8=daily
limit: Number of K-lines to retrieve
"""
url = f"https://api.itick.org/stock/kline?region={region}&code={symbol}&kType={k_type}&limit={limit}"
try:
response = requests.get(url, headers=headers)
data = response.json()
if data["code"] == 0: # Request successful
kline_list = data["data"]
df = pd.DataFrame(kline_list)
# Rename and format columns
df.rename(columns={'t': 'timestamp', 'o': 'open', 'h': 'high',
'l': 'low', 'c': 'close', 'v': 'volume'}, inplace=True)
df['datetime'] = pd.to_datetime(df['timestamp'], unit='s')
df.set_index('datetime', inplace=True)
df.sort_index(inplace=True) # Ensure chronological order
print(f"Successfully fetched {len(df)} K-lines for {symbol}")
return df[['open', 'high', 'low', 'close', 'volume']]
else:
print(f"Request failed: {data['msg']}")
return None
except Exception as e:
print(f"Error fetching data: {e}")
return None
# Example: Fetch daily data for Tencent Holdings (0700.HK)
df = fetch_kline_from_itick(symbol='700.HK', region='HK', k_type=8, limit=200)
print(df.head())
2. Calculating Moving Averages (MA)
Moving averages are the most basic trend indicators, used to smooth price data.
def calculate_ma(df, windows=[5, 10, 20]):
"""
Calculate Simple Moving Averages (SMA)
"""
for window in windows:
df[f'MA_{window}'] = df['close'].rolling(window=window).mean()
return df
# Calculate 5-day, 10-day, and 20-day moving averages
df = calculate_ma(df, [5, 10, 20])
print(df[['close', 'MA_5', 'MA_10', 'MA_20']].tail())
3. Calculating Exponential Moving Average (EMA) and MACD
MACD is a trend-following momentum indicator consisting of the fast line (DIF), slow line (DEA), and histogram (MACD Histogram).
def calculate_ema(series, period):
"""Calculate Exponential Moving Average (EMA)"""
return series.ewm(span=period, adjust=False).mean()
def calculate_macd(df, fast=12, slow=26, signal=9):
"""
Calculate MACD indicator
Standard parameters: fast period 12, slow period 26, signal period 9
"""
# Calculate fast and slow EMAs
df['EMA_Fast'] = calculate_ema(df['close'], fast)
df['EMA_Slow'] = calculate_ema(df['close'], slow)
# Calculate DIF (difference)
df['DIF'] = df['EMA_Fast'] - df['EMA_Slow']
# Calculate DEA (signal line: EMA of DIF)
df['DEA'] = calculate_ema(df['DIF'], signal)
# Calculate MACD histogram (typically 2 × (DIF - DEA))
df['MACD_Hist'] = 2 * (df['DIF'] - df['DEA'])
return df
# Calculate MACD
df = calculate_macd(df)
print(df[['close', 'DIF', 'DEA', 'MACD_Hist']].tail())
4. Calculating Relative Strength Index (RSI)
RSI is a momentum oscillator that measures the speed and magnitude of price movements to identify overbought or oversold conditions.
def calculate_rsi(df, window=14):
"""
Calculate Relative Strength Index (RSI)
"""
# Calculate price changes
delta = df['close'].diff()
# Separate gains and losses
gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
# Calculate Relative Strength (RS) and RSI
rs = gain / loss
df[f'RSI_{window}'] = 100 - (100 / (1 + rs))
return df
# Calculate 14-period RSI
df = calculate_rsi(df, window=14)
print(df[['close', 'RSI_14']].tail())
2. Data Visualization
Visualizing the price and indicators after calculation makes analysis more intuitive.
def plot_indicators(df, symbol='700.HK'):
"""Plot price, moving averages, MACD, and RSI charts"""
fig, axes = plt.subplots(3, 1, figsize=(14, 12), gridspec_kw={'height_ratios': [3, 2, 2]})
# Subplot 1: Price and Moving Averages
axes[0].plot(df.index, df['close'], label='Close Price', linewidth=1.5, color='black')
colors = ['blue', 'orange', 'green']
for i, period in enumerate([5, 10, 20]):
if f'MA_{period}' in df.columns:
axes[0].plot(df.index, df[f'MA_{period}'], label=f'MA{period}', alpha=0.8, color=colors[i])
axes[0].set_title(f'{symbol} - Price & Moving Averages')
axes[0].set_ylabel('Price')
axes[0].legend(loc='upper left')
axes[0].grid(True, alpha=0.3)
# Subplot 2: MACD
axes[1].plot(df.index, df['DIF'], label='DIF', color='blue', linewidth=1.5)
axes[1].plot(df.index, df['DEA'], label='DEA', color='red', linewidth=1.5)
# Histogram: green for positive, red for negative
colors_hist = ['green' if x >= 0 else 'red' for x in df['MACD_Hist']]
axes[1].bar(df.index, df['MACD_Hist'], color=colors_hist, alpha=0.5, width=0.8, label='MACD Hist')
axes[1].axhline(y=0, color='grey', linestyle='--', linewidth=0.8)
axes[1].set_ylabel('MACD')
axes[1].legend(loc='upper left')
axes[1].grid(True, alpha=0.3)
# Subplot 3: RSI
axes[2].plot(df.index, df['RSI_14'], label='RSI 14', color='purple', linewidth=1.5)
axes[2].axhline(y=70, color='red', linestyle='--', alpha=0.7, label='Overbought (70)')
axes[2].axhline(y=30, color='green', linestyle='--', alpha=0.7, label='Oversold (30)')
axes[2].axhline(y=50, color='grey', linestyle='--', alpha=0.5)
axes[2].set_ylabel('RSI')
axes[2].set_ylim(0, 100)
axes[2].legend(loc='upper left')
axes[2].grid(True, alpha=0.3)
axes[2].set_xlabel('Date')
plt.tight_layout()
plt.show()
# Plot the charts
plot_indicators(df, '700.HK')
3. Advanced: Generating Simple Trading Signals
Using the calculated indicators, we can create basic trading signals.
def generate_signals(df):
"""Generate simple trading signals based on MACD and RSI"""
df['signal'] = 0 # Initialize signal column
# Rule 1: RSI oversold (<30) + MACD golden cross (DIF crosses above DEA) → potential buy
rsi_oversold = df['RSI_14'] < 30
macd_golden_cross = (df['DIF'] > df['DEA']) & (df['DIF'].shift(1) <= df['DEA'].shift(1))
df.loc[rsi_oversold & macd_golden_cross, 'signal'] = 1 # Buy signal
# Rule 2: RSI overbought (>70) + MACD death cross (DIF crosses below DEA) → potential sell
rsi_overbought = df['RSI_14'] > 70
macd_death_cross = (df['DIF'] < df['DEA']) & (df['DIF'].shift(1) >= df['DEA'].shift(1))
df.loc[rsi_overbought & macd_death_cross, 'signal'] = -1 # Sell signal
return df
df_with_signals = generate_signals(df)
signal_points = df_with_signals[df_with_signals['signal'] != 0]
print("Trading signal points:")
print(signal_points[['close', 'RSI_14', 'DIF', 'DEA', 'signal']])
4. Summary and Practical Advice
By using market data APIs, we can easily obtain high-quality financial data and leverage Python’s powerful computation capabilities to implement core indicators like RSI, MACD, and moving averages from scratch. This gives you full flexibility and transparency when developing, testing, and optimizing quantitative strategies.
Key Recommendations:
- Understand the Indicators — Never use indicators blindly. Grasp the market implications behind RSI overbought/oversold levels, MACD golden/death crosses, and moving average alignments.
- Combine Multiple Indicators — A single indicator can have flaws (e.g., RSI can become desensitized in strong trends). Combining trend indicators (like MA) with momentum indicators (like RSI and MACD) improves signal reliability.
- Parameter Optimization and Backtesting — Indicator periods (e.g., RSI window, MACD fast/slow lines) are not fixed. Perform rigorous backtesting on different markets and assets to find optimal parameters.
- Risk Management — No technical indicator guarantees 100% accuracy. Always incorporate strict position sizing and stop-loss rules in real trading.
Reference: https://blog.itick.org/rsi-strategy-hands-on-guide-with-itick-data-python
GitHub: https://github.com/itick-org/
Top comments (0)