0bps

Strategy vault / Mean reversion

Stock Quant Trading Strategy Combining Exponential Moving Average with Trailing Stop Loss and Percentage Stop Loss

The core of this strategy is using exponential moving average crossovers as trading signals, combined with trailing stop loss and percentage stop loss to lock in profits and control risks. The strategy is simple to…

Author
ChaoZhang
Complexity
Intermediate · 118 lines
Parameters
6
Backtest bar
10m · intraday
Tested on
BTC/USDT · futures

IMG

Overview

The core of this strategy is using exponential moving average crossovers as trading signals, combined with trailing stop loss and percentage stop loss to lock in profits and control risks. The strategy is simple to implement and applicable to stocks and other financial products for quantitative trading.

Strategy Logic

  1. Calculate fast EMA and slow EMA, with fast EMA period being 20 days and slow EMA period being 50 days. Generate buy signal when fast EMA crosses above slow EMA, and sell signal when fast EMA crosses below slow EMA.

  2. After entry, set up trailing stop loss based on holding direction, e.g. 7% for long position and 7% for short position. The trailing stop loss adjusts every bar to lock in the maximum possible profit.

  3. At the same time, set stop loss price based on entry price and holding direction, e.g. 2% below entry price for long trade and 2% above entry price for short trade. The stop loss price remains unchanged to prevent excessive loss.

  4. Compare trailing stop price and stop loss price, use the one closer to market price as the final stop loss for this trade, send stop loss order.

Advantages

  1. Simple and easy to implement moving average trading signals.

  2. Trailing stop loss locks in profits to the largest extent possible, while avoiding unnecessary loss from false signals.

  3. Percentage stop loss is intuitive and easy to adjust for controlling maximum loss per trade.

  4. Combining trailing stops and fixed stops both locks in profits and controls risks.

Risks and Countermeasures

  1. Moving averages can generate false signals easily, add further filters like volume.

  2. Trailing stops sometimes trigger too early, relax the trailing percentage a bit.

  3. Improper fixed stop loss setting can be too aggressive or conservative, need to test and tune the percentage parameter.

  4. Mechanical stop loss exits could miss market reversal opportunities, incorporate technical indicators to judge stop trigger.

Optimization Directions

  1. Try different EMA combinations to find optimal balance.

  2. Add indicators like volume to filter false signals.

  3. Test more stocks to find suitable stop loss percentages.

  4. Try adaptive stops that adjust with market conditions.

  5. Incorporate indicators like RSI to determine stop loss timing.

Summary

This strategy integrates moving average trading signals, trailing stops and percentage stops. Through parameter optimization, it can achieve stable profits with strict risk control across various stocks and commodities, worth researching and continuously improving for quant traders.

Parameters

NameDefaultWhat it controls
v_input_int_120Fast EMA period
v_input_int_250Slow EMA period
v_input_float_17Long Trailing Stop (%)
v_input_float_27Short Trailing Stop (%)
v_input_float_32Long Stop Loss (%)
v_input_float_42Short Stop Loss (%)

Source Pine Script

/*backtest
start: 2023-12-26 00:00:00
end: 2024-01-02 00:00:00
period: 10m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © wouterpruym1828

//@version=5
strategy(title=" Combining Trailing Stop and Stop loss (% of instrument price)",
     overlay=true, pyramiding=1, shorttitle="TSL&SL%")

//INDICATOR SECTION

// Indicator Input options+
i_FastEMA = input.int(title = "Fast EMA period", minval = 0, defval = 20)
i_SlowEMA = input.int(title = "Slow EMA period", minval = 0, defval = 50)
     
// Calculate moving averages
fastEMA = ta.ema(close, i_FastEMA)
slowEMA = ta.ema(close, i_SlowEMA)

// Plot moving averages
plot(fastEMA, title="Fast SMA", color=color.blue)
plot(slowEMA, title="Slow SMA", color=color.orange)




//STRATEGY SECTION  

// Calculate trading conditions
buy  = ta.crossover(fastEMA, slowEMA)
sell = ta.crossunder(fastEMA, slowEMA)

// STEP 1:
// Configure trail stop loss level with input options (optional)

longTrailPerc = input.float(title="Long Trailing Stop (%)", minval=0.0, step=0.1, defval=7) * 0.01

shortTrailPerc = input.float(title="Short Trailing Stop (%)", minval=0.0, step=0.1, defval=7) * 0.01

//Configure stop loss level with input options (optional)

longStopPerc = input.float(title="Long Stop Loss (%)", minval=0.0, step=0.1, defval=2)*0.01

shortStopPerc = input.float(title="Short Stop Loss (%)", minval=0.0, step=0.1, defval=2)*0.01


// STEP 2:
// Determine trail stop loss prices
longTrailPrice = 0.0, shortTrailPrice = 0.0

longTrailPrice := if (strategy.position_size > 0)
    stopValue = high * (1 - longTrailPerc)
    math.max(stopValue, longTrailPrice[1])
else
    0

shortTrailPrice := if (strategy.position_size < 0)
    stopValue = low * (1 + shortTrailPerc)
    math.min(stopValue, shortTrailPrice[1])
else
    999999

// Determine stop loss prices
entryPrice = 0.0

entryPrice := strategy.opentrades.entry_price(strategy.opentrades - 1)


longLossPrice = entryPrice * (1 - longStopPerc)

shortLossPrice = entryPrice * (1 + shortStopPerc)


// Plot stop loss values for confirmation

plot(series=(strategy.position_size > 0) ? longTrailPrice : na,
     color=color.fuchsia, style=plot.style_cross,
     linewidth=2, title="Long Trail Stop")
plot(series=(strategy.position_size < 0) ? shortTrailPrice : na,
     color=color.fuchsia, style=plot.style_cross,
     linewidth=2, title="Short Trail Stop")

plot(series=(strategy.position_size > 0) ? longLossPrice : na,
     color=color.olive, style=plot.style_cross,
     linewidth=2, title="Long Stop Loss")
plot(series=(strategy.position_size < 0) ? shortLossPrice : na,
     color=color.olive, style=plot.style_cross,
     linewidth=2, title="Short Stop Loss")

// Submit entry orders
if (buy)
    strategy.entry("Buy", strategy.long)

if (sell)
    strategy.entry("Sell", strategy.short)


//Evaluating trailing stop or stop loss to use

longStopPrice = longTrailPrice < longLossPrice ? longLossPrice : longTrailPrice

shortStopPrice = shortTrailPrice > shortLossPrice ? shortLossPrice : shortTrailPrice

// STEP 3:
// Submit exit orders for stop price

if (strategy.position_size > 0)
    strategy.exit(id="Buy Stop", stop=longStopPrice)

if (strategy.position_size < 0)
    strategy.exit(id="Sell Stop", stop=shortStopPrice)

Published by ChaoZhang on the FMZ strategy square · last modified 2024-01-03. 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/Stock-Quant-Trading-Strategy-Combining-Exponential-Moving-Average-with-Trailing-Stop-Loss-and-Percentage-Stop-Loss.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