0bps

Strategy vault / Machine learning

The Double EMA Strategy Analysis

The double EMA strategy is a trend following strategy that identifies the trend direction of prices by calculating EMAs of different cycles and uses that to determine entries and exits. This simple and practical…

Author
ChaoZhang
Complexity
Intermediate · 98 lines
Parameters
9
Backtest bar
1d · swing
Tested on
BTC/USDT · futures

IMG

Overview

The double EMA strategy is a trend following strategy that identifies the trend direction of prices by calculating EMAs of different cycles and uses that to determine entries and exits. This simple and practical strategy works well in trending markets.

Strategy Logic

The strategy is mainly based on two EMA indicators, a short-term 9-day EMA and a longer 21-day EMA. Their crossovers generate entry and exit signals.

When the short EMA crosses above the long EMA, it is viewed as prices entering an uptrend. The strategy will go long to follow the rising trend. When the short EMA crosses below the long EMA, it is viewed as prices entering a downtrend. The strategy will go short to follow the falling trend.

The EMA indicators can effectively filter out noise from price data and identify the main direction of the trend. Therefore, the strategy uses dual EMAs as the basis for entries and exits in order to capture longer price trends.

Advantages

The strategy has the following advantages:

  1. The strategy idea is simple and easy to understand and implement.
  2. It can effectively identify price trends and timely enter positions to follow trends.
  3. Using EMAs filters noise and avoids interference from short-term price fluctuations.
  4. The EMA parameters can be configured to adjust the sensitivity of the strategy.

Risks

There are also some risks with this strategy:

  1. The lagging characteristic of EMAs may increase losses when trends reverse.
  2. Improper EMA parameter settings increase false signal rates.
  3. The strategy is more suitable for strong trending markets and vulnerable in range-bound periods.

Enhancement

The strategy can be optimized in the following aspects:

  1. Incorporate other indicators to identify trend reversals and reduce losses, e.g. MACD, KDJ, etc.
  2. Add stop loss logic. Good stop loss strategies can greatly reduce maximum drawdown.
  3. Optimize the EMA parameters to make them fit better with the price characteristics of different products.
  4. Use machine learning algorithms to automate EMA parameter optimization.

Summary

In summary, the double EMA strategy is a very useful trend following strategy. It is easy to operate, understand, and performs excellently in strong trending markets. The strategy also has some risks that can be mitigated through various enhancements to improve its stability. Overall, double EMAs serve as an important reference template for quantitative trading.

Parameters

NameDefaultWhat it controls
v_input_19Short EMA Length
v_input_221Long EMA Length
v_input_color_1close[1]>openLPrice?LongWColor:LongLColor,.rgb(0,255,0,0)(?Strategy Lines)Long Win Color
v_input_color_2close[1]>openLPrice?LongWColor:LongLColor,.rgb(0,0,255,0)Long Loss Color
v_input_color_3close[1]>openLPrice?LongWColor:LongLColor,.rgb(255,255,0,0)Short Win Color
v_input_color_4close[1]>openLPrice?LongWColor:LongLColor,.rgb(255,0,0,0)Short Loss Color
v_input_color_5close[1]>openLPrice?LongWColor:LongLColor,.rgb(0,0,0,0)Win Font Color
v_input_color_6close[1]>openLPrice?LongWColor:LongLColor,.rgb(255,255,255,0)Loss Font Color
v_input_3falseShow Labels?

Source Pine Script

/*backtest
start: 2023-02-21 00:00:00
end: 2024-02-27 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=5
// This can only draw so many lines. Use bar replay to go back further
strategy("Strategy Lines", shorttitle="Strategy Lines", overlay=true, max_lines_count=500)

//###########################################################################################################################################
// Replace your strategy here
//###########################################################################################################################################

shortEMA = ta.ema(close, input(9, title="Short EMA Length"))
longEMA = ta.ema(close, input(21, title="Long EMA Length"))

// Entry conditions for long and short positions
longCondition = ta.crossover(shortEMA, longEMA)
shortCondition = ta.crossunder(shortEMA, longEMA)

//###########################################################################################################################################
// Strategy Lines
//###########################################################################################################################################

var timeLow = bar_index
var line li = na
var openLPrice = 0.0000
var openSPrice = 0.0000

LongWColor = input.color(color.rgb(0,255,0,0),"Long Win Color", group="Strategy Lines")
LongLColor = input.color(color.rgb(0,0,255,0),"Long Loss Color", group="Strategy Lines")
ShortWColor = input.color(color.rgb(255,255,0,0),"Short Win Color", group="Strategy Lines")
ShortLColor = input.color(color.rgb(255,0,0,0),"Short Loss Color", group="Strategy Lines")
WinFontColor = input.color(color.rgb(0,0,0,0),"Win Font Color", group="Strategy Lines")
LossFontColor = input.color(color.rgb(255,255,255,0),"Loss Font Color", group="Strategy Lines")
LinesShowLabel = input(false,"Show Labels?",group = "Strategy Lines")

// // Start new line when we go long
// if strategy.position_size >0
//     line.delete(li)
//     li := line.new(timeLow, close[bar_index-timeLow], bar_index, close, width=2, color=close>openLPrice?LongWColor:LongLColor)

// // Start new line when we go short
// if strategy.position_size <0
//     line.delete(li)
//     li := line.new(timeLow, close[bar_index-timeLow], bar_index, close, width=2, color=close<openSPrice?ShortWColor:ShortLColor)

// //Delete Lines if we don't have a position open
// if strategy.position_size ==0
//     li := line.new(timeLow, close[bar_index-timeLow], bar_index, close, width=2, color=color.rgb(0,0,0,100))
//     line.delete(li)

if LinesShowLabel
    // Short Label
    if strategy.position_size>=0 and strategy.position_size[1] <0
        label.new(
             timeLow, na, 
             text=str.tostring((openSPrice-close[1])/(syminfo.mintick*10)), 
             color=close[1]<openSPrice?ShortWColor:ShortLColor, 
             textcolor=close[1]<openSPrice?WinFontColor:LossFontColor,
             size=size.small, 
             style=label.style_label_down, yloc=yloc.abovebar)
    // Long Label
    if strategy.position_size<=0 and strategy.position_size[1] >0
        label.new(
             timeLow, na,
             text=str.tostring((close[1]-openLPrice)/(syminfo.mintick*10)), 
             color=close[1]>openLPrice?LongWColor:LongLColor, 
             textcolor=close[1]>openLPrice?WinFontColor:LossFontColor,
             size=size.small, 
             style=label.style_label_down, yloc=yloc.abovebar)

// Open long position and draw line
if (longCondition)
    //strategy.entry("Long", strategy.long)
    // timeLow := bar_index
    // li := line.new(timeLow, close[bar_index-timeLow], bar_index, close, width=2, color=close>openLPrice?LongWColor:LongLColor)
    openLPrice := close

// Open short position and draw line
if (shortCondition)
    //strategy.entry("Short", strategy.short)
    // timeLow := bar_index
    // li := line.new(timeLow, close[bar_index-timeLow], bar_index, close, width=2, color=close<openSPrice?ShortWColor:ShortLColor)
    openSPrice := close

//###########################################################################################################################################
// Strategy Execution (Replace this as well)
//###########################################################################################################################################

if (longCondition)
    strategy.entry("Long", strategy.long)

if (shortCondition)
    strategy.entry("Short", strategy.short)

Published by ChaoZhang on the FMZ strategy square · last modified 2024-02-28. Collected in the Quant Trading Vault. Unvalidated research: re-test with your own data and costs before trusting it.

Build this with AgenKit

A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.

in Claude Code, Cursor, Codex & 4 more
/agenkit build a production-grade trading bot with a backtest engine, risk controls and paper trading by default from strategies/The-Double-EMA-Strategy-Analysis.md
  1. npx agenkit install engineering-kit in your project
  2. Paste the command into your agent and approve each phase
  3. Get tests, backtest, risk controls and a paper-trading switch

Understand it first

Before you run this, read the lesson behind the idea and how to backtest it honestly. Specs like this one are the survivors of an unknown number of trials; deflate their results accordingly.

Related specs

esc

Try , , or .

↑↓ move↵ open