- GuruFinance Insights
- Posts
- Enhancing EMA Cross Strategies with AI: An AMZN Case Study
Enhancing EMA Cross Strategies with AI: An AMZN Case Study
Exciting News: Paid Subscriptions Have Launched! 🚀
On September 1, we officially rolled out our new paid subscription plans at GuruFinance Insights, offering you the chance to take your investing journey to the next level! Whether you're just starting or are a seasoned trader, these plans are packed with exclusive trading strategies, in-depth research paper analysis, ad-free content, monthly AMAsessions, coding tutorials for automating trading strategies, and much more.
Our three tailored plans—Starter Investor, Pro Trader, and Elite Investor—provide a range of valuable tools and personalized support to suit different needs and goals. Don’t miss this opportunity to get real-time trade alerts, access to masterclasses, one-on-one strategy consultations, and be part of our private community group. Click here to explore the plans and see how becoming a premium member can elevate your investment strategy!
Check Out Latest Premium Articles
Fig 1: Amazon backtesting results for standard EMA values (50, 200 days)
Fig 2: Amazon backtesting results using AI optimized EMA values (see Section 5)
1. Introduction
Moving averages, particularly Exponential Moving Averages (EMAs), have long been staples for traders seeking to capture momentum and time their trade entries and exits. While popular configurations such as the 50-day and 200-day EMAs are widely used, they often fail to account for the unique behavior of individual stocks or asset classes. In this article, we explore how AI can revolutionize EMA cross strategies by customizing these averages for specific assets. Using AMZN as our focal point, we’ll compare the outcomes of traditional EMA setups with AI-optimized alternatives, revealing a substantial performance gap.
2. Why EMAs are Vital for Traders
EMAs place greater emphasis on recent price movements, offering a more dynamic response to market trends than simple moving averages (SMAs). Traders often pair a "fast" EMA with a "slow" EMA to identify momentum shifts. A typical strategy involves buying when the fast EMA moves above the slow EMA (bullish crossover) and selling when it falls below (bearish crossover).
However, the success of this strategy hinges on selecting the right periods for the fast and slow EMAs. While common settings like 50-day and 200-day EMAs might work reasonably well for some assets, they can underperform for others. Enter AI—a game changer that eliminates guesswork.
3. The Limitations of Generic EMA Settings
The ubiquitous 50/200-day EMA combination may seem like a universal solution, but it often falls short for certain stocks, especially high-growth or highly volatile ones like AMZN. AMZN's distinct growth trajectory and volatility characteristics demand a tailored approach.
To put this theory to the test, we conducted backtests on AMZN spanning 2004 to 2024, comparing results from standard and optimized EMA configurations. The findings were stark: the standard settings significantly underperformed, underscoring the need for a customized methodology for such dynamic assets.
4. Leveraging AI to Optimize EMA Crossovers
AI-driven tools such as Backtesting.py
have unlocked a new frontier in trading strategies, enabling us to identify optimal EMA configurations through extensive simulations. Here’s how the process works:
Data Gathering: Using libraries like
yfinance
, we collected AMZN’s historical price data.Comprehensive Backtesting: By running thousands of combinations of fast and slow EMAs, we evaluated performance against various metrics.
Optimization with AI: We prioritized metrics like the Sortino Ratio, which measures risk-adjusted returns by focusing on downside risk.
Through this approach, we identified radically different EMA settings for AMZN. The optimized fast/slow EMA combination for long trades was 21/197, while for short trades, it was 151/165—departing significantly from the standard 50/200-day configuration.
5. Standard vs. Optimized EMA Performance: The Results
After applying both standard and optimized EMA setups to AMZN, the contrast in performance was remarkable.
Performance Metrics
Standard EMA Settings:
Total Return: 196.53%
Maximum Drawdown: 77.72%
Sharpe Ratio: 0.14
Total Trades: 23
Optimized EMA Settings:
Total Return: 2386.73%
Maximum Drawdown: 59.03%
Sharpe Ratio: 0.43
Total Trades: 21
Not only did the optimized strategy deliver over 10 times higher returns, but it also achieved better risk-adjusted performance, as evident in the improved Sharpe Ratio. Additionally, it required fewer trades, signaling more precise entry and exit points. This highlights how AI’s ability to fine-tune strategies can deliver exceptional results.
6. Putting the Optimized Strategy into Action
To implement the AI-optimized EMA strategy, you can leverage Python’s robust ecosystem. Below is a simplified script using Backtesting.py
and yfinance
to replicate this strategy on AMZN or adapt it to other assets.
EMACrossSwing.py
import pandas_ta as ta
import pandas as pd
from backtesting import Backtest, Strategy
from backtesting.lib import crossover, resample_apply
import json
import os
from datetime import datetime
class EmaCrossSwing(Strategy):
# default values for EMA
n1_long = 50
n2_long = 100
n1_short = 50
n2_short = 100
rsi_period = 14
def init(self):
close = pd.Series(self.data.Close, index=self.data.index)
self.ema1_long = self.I(ta.ema, close, self.n1_long)
self.ema2_long = self.I(ta.ema, close, self.n2_long)
self.ema1_short = self.I(ta.ema, close, self.n1_short)
self.ema2_short = self.I(ta.ema, close, self.n2_short)
# Ensure close has a DatetimeIndex
if not isinstance(close.index, pd.DatetimeIndex):
close.index = pd.to_datetime(close.index)
def next(self):
# Entry signals
if crossover(self.ema1_long, self.ema2_long):
if self.position.is_short:
self.position.close()
self.buy()
elif crossover(self.ema2_long, self.ema1_long):
if self.position.is_long:
self.position.close()
if crossover(self.ema2_short, self.ema1_short):
if self.position.is_long:
self.position.close()
self.sell()
elif crossover(self.ema1_short, self.ema2_short):
if self.position.is_short:
self.position.close()
def run_ema_cross_swing_strategy(data, params=None, maximize='Sortino Ratio', max_tries=300):
bt = Backtest(data, EmaCrossSwing, cash=1_000_000, commission=.002, hedging=True)
if params:
for key, value in params.items():
setattr(EmaCrossSwing, key, value)
output = bt.run()
else:
output, heatmap = bt.optimize(
n1_long=range(10, 200, 1),
n2_long=range(20, 200, 1),
n1_short=range(5, 200, 1),
n2_short=range(10, 200, 1),
#rsi_period=range(5, 30, 1),
#rsi_overbought=range(65, 85, 1),
#rsi_oversold=range(15, 35, 1),
maximize=maximize,
method='skopt',
constraint=lambda p: p.n1_long < p.n2_long and p.n1_short < p.n2_short, #and p.rsi_oversold < p.rsi_overbought,
return_heatmap=True,
max_tries=max_tries
)
# Extract optimal parameters and ensure keys are strings
if isinstance(heatmap, pd.Series):
optimal_params = {str(k): v for k, v in heatmap.to_dict().items()}
else:
optimal_params = {str(k): v for k, v in heatmap.iloc[heatmap[heatmap.columns[-1]].idxmax()].to_dict().items()}
# Save optimal parameters to JSON
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
output_filename = f"output/{data.index[0].strftime('%Y%m%d')}_swing_optimal_params_{timestamp}.json"
os.makedirs(os.path.dirname(output_filename), exist_ok=True)
with open(output_filename, 'w') as f:
json.dump(optimal_params, f, indent=4)
bt.plot(resample=False)
return output
main.py
import logging
import pandas as pd
import yfinance as yf
from datetime import datetime
import os
import json
from strategies.EmaCrossSwing import run_ema_cross_swing_strategy
def setup_logging():
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
log_filename = f"log/ema_cross_swing_{timestamp}.log"
os.makedirs(os.path.dirname(log_filename), exist_ok=True)
logging.basicConfig(filename=log_filename, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logging.getLogger().addHandler(logging.StreamHandler())
def fetch_yfinance_data(ticker, start_date, end_date):
data = yf.download(ticker, start=start_date, end=end_date, interval='1d')
return data
def save_results_to_json(output, filename):
os.makedirs(os.path.dirname(filename), exist_ok=True)
filtered_output = {k: v for k, v in output.items() if k not in ['MSE', 'R2', '_equity_curve', '_trades']}
with open(filename, 'w') as f:
json.dump(filtered_output, f, indent=4)
def main():
# Setup logging
setup_logging()
# Define default parameters
ticker = "AMZN"
start_date = "2004-01-01"
end_date = datetime.today().strftime('%Y-%m-%d')
max_tries = 300
maximize = "Sortino Ratio"
# Fetch data
data = fetch_yfinance_data(ticker, start_date, end_date)
# Run the strategy
output = run_ema_cross_swing_strategy(data, None, maximize, max_tries)
# Save the results
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
output_filename = f"output/{ticker}_ema_cross_swing_{timestamp}_params.json"
save_results_to_json(output, output_filename)
logging.info(f"Results saved to {output_filename}")
print(output)
if __name__ == '__main__':
main()
5. Evaluating Optimal Parameters
Upon running the script, the best parameters identified for AMZN are:
{
"n1_long": 21,
"n2_long": 197,
"n1_short": 151,
"n2_short": 165
}
Key Parameter Interpretations:
n1_long (21): Refers to the shorter EMA period for long trades. This 21-day setting reacts quickly to recent price movements, aiding in the identification of rapid trend changes.
n2_long (197): Indicates the longer EMA period for long trades. The 197-day period smoothens short-term fluctuations, helping to recognize sustained, long-term trends.
n1_short (151): Represents the shorter EMA period for short trades. Being longer than n1_long, this setting suggests a careful approach to initiating short positions, acting only on significant price shifts.
n2_short (165): Refers to the longer EMA period for short trades. Although also a lengthy period, it’s shorter than n2_long, making it suitable for tracking moderately extended downtrends.
Analysis of Parameters
Contrast Between Long and Short Settings:
The EMA periods for short trades (n1_short and n2_short) are longer than n1_long, signaling a conservative stance on short-selling. This indicates a strategy that prioritizes taking advantage of bullish trends over bearish moves.Balancing Responsiveness and Stability:
A notable difference exists between n1_long and n2_long, reflecting a strategy designed to capture emerging upward trends while avoiding noise. Conversely, the narrower gap between n1_short and n2_short reveals a more cautious approach to short trades.Trading Implications:
These parameters are tailored to perform well in trending markets, particularly when trends are pronounced. However, the focus on longer periods may lead to challenges in high-volatility or range-bound markets. The reliance on longer EMAs implies a preference for identifying substantial, sustained price movements rather than frequent, short-term trades.
This breakdown demonstrates the strategy’s aim to balance trend capture with the avoidance of false signals. However, its exclusive reliance on EMAs might lead to missed opportunities, particularly those indicated by momentum or volatility-based measures.
6. Final Thoughts
This analysis underscores the advantage of employing AI to refine trading strategies, especially for individual assets like AMZN that don’t necessarily align with conventional EMA configurations, such as those often used for broad indices like the S&P 500 or NASDAQ-100. Customizing parameters to suit specific assets can significantly enhance both returns and risk management.
While optimizing EMA values provides meaningful benefits, depending solely on EMAs introduces risks, such as false signals in non-trending markets, overfitting to historical data, and potential for considerable drawdowns. A more robust approach that integrates various technical indicators could better mitigate these risks, ensuring consistent performance across different market environments.
Whether you’re trading AMZN or any other security, adapting EMA settings to align with your chosen asset is crucial. Tailoring your approach can lead to far better portfolio outcomes.
Disclaimer
This material is for informational purposes only and does not constitute financial advice. Trading carries risks, and you should consult with a professional financial advisor before making investment decisions.