After spending time on quantitative strategies, I’ve realized that relying on a single signal rarely works in all market conditions. Momentum indicators perform well in trending markets, but they can fail completely in sideways movements. Recently, I shifted my focus from “finding the best signal” to “how signals work together.” My latest experiment combines momentum, volatility, and trend strength factors to see how they interact and how the combined strategy performs.
Before diving in, I had to tackle two points:
- Data needs to be reliable and cover multiple markets.
- Factors must be on a comparable scale to ensure fair combination.
To address this, I retrieve historical data from multi-market interfaces. Taking EURUSD daily data as an example, provided by AllTick, we can observe how different factors behave over the same time window, which makes it easier to validate the stability of the combined signals.
Constructing Factor Signals
For this experiment, I defined three core signals:
- Momentum factor: the z-score of recent returns, capturing trend continuation.
- Volatility factor: measuring how choppy the market is; lower volatility often indicates more reliable trends.
- Trend strength factor: the deviation of price from a long-term moving average, reflecting trend intensity.
Each factor represents a different market behavior. Combining them is intended to reduce the chance of failure in various market states. To make them comparable, I standardized each factor before aggregation.
Here’s an example of how to pull AllTick API data and calculate a composite factor score:
import requests
import pandas as pd
import numpy as np
# Example: EURUSD daily data from AllTick
def fetch_alltick_ohlcv(symbol, start, end):
url = "https://api.alltick.co/v1/ohlcv"
params = {
"symbol": symbol,
"interval": "1d",
"start": start,
"end": end
}
res = requests.get(url, params=params).json()
df = pd.DataFrame(res["data"])
df.set_index("time", inplace=True)
return df
def composite_factor(df):
mom = df['close'].pct_change(5).rolling(5).mean()
vol = df['close'].rolling(10).std()
trend = df['close'] - df['close'].ewm(span=20).mean()
mom_z = (mom - mom.mean()) / mom.std()
vol_z = - (vol - vol.mean()) / vol.std() # lower volatility considered safer
trend_z = (trend - trend.mean()) / trend.std()
return mom_z + vol_z + trend_z
df = fetch_alltick_ohlcv("EURUSD", "20220101", "20231231")
df["score"] = composite_factor(df)
Backtesting Insights
After applying the composite factor to a simple backtesting framework, I noticed three things:
- Smoother risk control
In sideways markets, pure momentum often triggers frequent signals, causing unnecessary turnover. Including the volatility factor suppresses high-volatility signals, resulting in smoother performance. - Stronger performance in trends
Trend strength acts as an “accelerator” in trending markets, boosting the composite score and allowing the strategy to capture directional moves earlier. - Reduced extreme drawdowns
Maximum drawdowns are noticeably smaller than those of single-factor strategies. Absolute returns may not always exceed the individual factors, but the drawdown control improves durability, which is crucial in live trading.
These observations show that factor combination is not mere stacking. It provides alternative signal paths under different market behaviors.
Personal Thoughts
This experiment reinforced a key idea: quantitative strategies aim to understand market behavior, not predict the future. Chasing a “perfect” indicator is futile; the most sustainable strategies combine market structure understanding, multiple signals, and risk management.
Every backtest is an opportunity to observe how factors perform under different conditions: which signals remain reliable when the market changes, and where adjustments are needed when drawdowns increase. These questions are far more valuable than simply producing a smooth equity curve.
Through this multi-factor experiment, I’ve started to focus more on the logic behind the numbers rather than chasing profits alone, which gives strategies better stability and interpretability when moving to live trading.
