The main idea of this strategy is to use the breakout band to identify trend direction and combine fixed stop loss for risk management. The strategy first calculates the highest and lowest prices over a certain period to form a breakout band. When the price breaks through the breakout band, a trading signal is generated. In addition, the strategy allows traders to set a fixed stop loss amount. Each time a trade is placed, the system will calculate the position size based on the fixed stop loss amount, so that each loss is fixed.
The strategy consists of four main parts: position management, breakout band identification, stop loss setting and position sizing.
Firstly, the strategy checks if there is any open position. If there is, no new signals will be generated.
Secondly, the strategy calculates the highest and lowest prices over a period to form a breakout band. When the price breaks out of the band, a trading signal is generated. Specifically, if the price breaks above the upper band, a long signal is generated. If the price breaks below the lower band, a short signal is generated.
In addition, when a long signal is generated, the strategy sets the midpoint of the breakout band as the stop loss. The same goes for short signals. To trail the stop loss, the strategy also adjusts the stop loss in real-time when in position.
Finally, the strategy allows setting a fixed stop loss amount. When a signal is generated, the strategy calculates the number of pips from stop loss to current price, and combines factors like tick size and exchange rate, to determine the price change between stop loss and current price in monetary terms. The position size is then calculated based on the fixed stop loss amount.
Above are the main principles of the strategy. Identifying trend direction with breakout bands and controlling risk with fixed stop loss are the core concepts.
This breakout band fixed stop loss strategy has the following advantages:
Advanced stop loss concept. The strategy uses fixed stop loss amount instead of fixed stop loss distance. This avoids the problem of unable to fix risk across products with different tick values. From a risk management perspective, fixed monetary stop loss is more advanced.
Reasonable position sizing. The strategy can intelligently calculate position size based on the fixed stop loss amount, so that the loss per trade is controlled, thereby reasonably managing risk exposure.
Simple and effective breakout identification. Identifying breakout with bands is simple and direct, and can effectively identify trend direction. Compared to breakout of a single price level, this breakout band identification can avoid more false signals away from the trend.
Trailing stop loss increases profit. The strategy’s ability to adjust stop loss in real-time for trailing stop loss helps lock in more profits.
Wide applicability. The strategy is applicable to any products. As long as parameters are set properly, fixed amount stop loss risk control can be achieved, making the strategy highly versatile.
Clean code structure. The code structure is clear and modular, making it easy to understand and optimize.
Despite the advantages, there are some risks to note for the strategy:
Breakout pattern quality untested. The strategy does not judge breakout pattern quality and may generate some low quality signals. Other indicators are needed to filter signals.
Fixed stop loss may be too mechanical. Market prices often gap. Fixed stop loss may rely too much on rules and lacks flexibility in adjustment.
No limit on trade frequency. The strategy does not limit trade frequency and may trade too often. Other rules are needed to limit frequency.
Fixed stop loss depends on parameter setting. Setting fixed stop loss amount is crucial for overall risk control and needs to consider capital size, risk appetite etc.
Breakout direction may give wrong signals. Wrong breakout signals may occur during price oscillations or pullbacks. More conditions are needed to optimize the strategy.
No profit taking mechanism. The strategy currently has no profit taking capability to actively lock in profits. This may lead to unsatisfactory profits.
To address these risks, some ways to optimize the strategy include:
Adding indicators to filter signal quality, e.g. MACD, KD etc.
Incorporating breakout strength indicators to evaluate quality. For example, judging strength through volume changes.
Adding open trade frequency limits, e.g. one trade per day.
Optimizing fixed stop loss logic, e.g. percentage-based stop loss above a threshold.
Adding other filters, e.g. volatility, enhance stop loss etc.
Incorporating profit taking strategies, e.g. taking profit near resistance.
Based on the analysis, the strategy can be optimized in the following aspects:
Adding filters to improve signal quality using multiple technical indicators and assessing trend quality. Also judging breakout strength.
Optimizing stop loss for more flexibility. Can switch to percentage-based trailing stop after a certain retracement. Can also optimize dynamically based on volatility.
Controlling trade frequency to avoid over-trading by adding filters on time periods or frequency.
Incorporating trend indicators to improve timing, e.g. waiting for trend confirmation.
Optimizing profit taking strategies to improve profitability via profit target, trailing profit stop, volatility stop etc.
Optimizing risk parameters based on backtests, such as fixed stop amount, breakout period etc.
Refactoring code for better extensibility by further decoupling signal, filter, risk, profit modules.
Testing more products for arbitrage opportunities. Evaluate advantage across different product combinations.
Through these optimization dimensions, the breakout stop loss strategy can become more robust and profitable. It also lays the foundation for expanding into more strategy combinations.
Overall the strategy is reasonable in using breakout bands to identify trends and fixed amount stops for risk control. The concepts are progressive for risk management. The position sizing logic is also sound for controlling loss per trade. But the strategy can be enhanced through various optimizations to improve signal quality, flexibility in stop loss, profitability etc. By incorporating trend filters, improving profit taking, and strictly controlling trade frequency, significant improvement can be achieved. In conclusion, the strategy provides a framework for learning risk management and position sizing techniques, laying the groundwork for further research into more complex arbitrage and multi-strategy systems.
/*backtest start: 2023-10-26 00:00:00 end: 2023-10-28 03: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/ //@version=4 //@author=Takazudo strategy("Fixed price SL", overlay=true, default_qty_type=strategy.fixed, initial_capital=0, currency=currency.USD) var COLOR_TRANSPARENT = color.new(#000000, 100) var COLOR_ENTRY_BAND = color.new(#43A6F5, 30) //============================================================================ // config //============================================================================ // Money management _g1 = 'Money management' var config_riskPrice = input(100, minval=1, title="Risk price for each entry", group=_g1) var config_depositCurrency = input(title="Deposit currency", type=input.string, defval="USD", options=["USD"], group=_g1) // Entry strategy _g2 = 'Entry strategy' var config_entryBandBars = input(defval = 100, title = "Entry band bar count", minval=1, group=_g2) // Backtesting range _g3 = 'Backtesting range' fromYear = input(defval = 2018, title = "From Year", minval = 1970, group=_g3) fromMonth = input(defval = 1, title = "From Month", minval = 1, maxval = 12, group=_g3) fromDay = input(defval = 1, title = "From Day", minval = 1, maxval = 31, group=_g3) toYear = input(defval = 2020, title = "To Year", minval = 1970, group=_g3) toMonth = input(defval = 12, title = "To Month", minval = 1, maxval = 12, group=_g3) toDay = input(defval = 31, title = "To Day", minval = 1, maxval = 31, group=_g3) //============================================================================ // exchange caliculations //============================================================================ // mico pip size caliculation // ex1: AUDCAD -> 0.0001 // ex2: USDJPY -> 0.01 f_calcMicroPipSize() => _base = syminfo.basecurrency _quote = syminfo.currency _result = 0.0001 if _quote == 'JPY' _result := _result * 100 if _base == 'BTC' _result := _result * 100 _result // convert price to pips f_convertPriceToPips(_price) => _microPipSize = f_calcMicroPipSize() _price / _microPipSize // caliculate exchange rate between deposit and quote currency f_calcDepositExchangeSymbolId() => _result = '' _deposit = config_depositCurrency _quote = syminfo.currency if (_deposit == 'USD') and (_quote == 'USD') _result := na if (_deposit == 'USD') and (_quote == 'AUD') _result := 'OANDA:AUDUSD' if (_deposit == 'EUR') and (_quote == 'USD') _result := 'OANDA:EURUSD' if (_deposit == 'USD') and (_quote == 'GBP') _result := 'OANDA:GBPUSD' if (_deposit == 'USD') and (_quote == 'NZD') _result := 'OANDA:NZDUSD' if (_deposit == 'USD') and (_quote == 'CAD') _result := 'OANDA:USDCAD' if (_deposit == 'USD') and (_quote == 'CHF') _result := 'OANDA:USDCHF' if (_deposit == 'USD') and (_quote == 'JPY') _result := 'OANDA:USDJPY' _result // Let's say we need CAD to USD exchange // However there's only "OANDA:USDCAD" symbol. // Then we need to invert the exhchange rate. // this function tells us whether we should invert the rate or not f_calcShouldInvert() => _result = false _deposit = config_depositCurrency _quote = syminfo.currency if (_deposit == 'USD') and (_quote == 'CAD') _result := true if (_deposit == 'USD') and (_quote == 'CHF') _result := true if (_deposit == 'USD') and (_quote == 'JPY') _result := true _result // caliculate how much quantity should I buy or sell f_calcQuantitiesForEntry(_depositExchangeRate, _slPips) => _microPipSize = f_calcMicroPipSize() _priceForEachPipAsDeposit = _microPipSize * _depositExchangeRate _losePriceOnSl = _priceForEachPipAsDeposit * _slPips floor(config_riskPrice / _losePriceOnSl) //============================================================================ // Quantity caliculation //============================================================================ depositExchangeSymbolId = f_calcDepositExchangeSymbolId() // caliculate deposit exchange rate rate = security(depositExchangeSymbolId, timeframe.period, hl2) shouldInvert = f_calcShouldInvert() depositExchangeRate = if config_depositCurrency == syminfo.currency // if USDUSD, no exchange of course 1 else // else, USDCAD to CADUSD invert if we need shouldInvert ? (1 / rate) : rate //============================================================================ // Range Edge caliculation //============================================================================ f_calcEntryBand_high() => _highest = max(open[3], close[3]) for i = 4 to (config_entryBandBars - 1) _highest := max(_highest, open[i], close[i]) _highest f_calcEntryBand_low() => _lowest = min(open[3], close[3]) for i = 4 to (config_entryBandBars - 1) _lowest := min(_lowest, open[i], close[i]) _lowest entryBand_high = f_calcEntryBand_high() entryBand_low = f_calcEntryBand_low() entryBand_height = entryBand_high - entryBand_low plot(entryBand_high, color=COLOR_ENTRY_BAND, linewidth=1) plot(entryBand_low, color=COLOR_ENTRY_BAND, linewidth=1) rangeBreakDetected_long = entryBand_high < close rangeBreakDetected_short = entryBand_low > close shouldMakeEntryLong = (strategy.position_size == 0) and rangeBreakDetected_long shouldMakeEntryShort = (strategy.position_size == 0) and rangeBreakDetected_short //============================================================================ // SL & Quantity //============================================================================ var sl_long = hl2 var sl_short = hl2 entryQty = 0 slPips = 0.0 // just show info bubble f_showEntryInfo(_isLong) => _str = 'SL pips: ' + tostring(slPips) + '\n' + 'Qty: ' + tostring(entryQty) _bandHeight = entryBand_high - entryBand_low _y = _isLong ? (entryBand_low + _bandHeight * 1/4) : (entryBand_high - _bandHeight * 1/4) _style = _isLong ? label.style_label_up : label.style_label_down label.new(bar_index, _y, _str, size=size.large, style=_style) if shouldMakeEntryLong sl_long := (entryBand_high + entryBand_low) / 2 slPips := f_convertPriceToPips(close - sl_long) entryQty := f_calcQuantitiesForEntry(depositExchangeRate, slPips) if shouldMakeEntryShort sl_short := (entryBand_high + entryBand_low) / 2 slPips := f_convertPriceToPips(sl_short - close) entryQty := f_calcQuantitiesForEntry(depositExchangeRate, slPips) // trailing SL if strategy.position_size > 0 sl_long := max(sl_long, entryBand_low) if strategy.position_size < 0 sl_short := min(sl_short, entryBand_high) //============================================================================ // backtest duration //============================================================================ // Calculate start/end date and time condition startDate = timestamp(fromYear, fromMonth, fromDay, 00, 00) finishDate = timestamp(toYear, toMonth, toDay, 00, 00) //============================================================================ // make entries //============================================================================ if (true) if shouldMakeEntryLong strategy.entry(id="Long", long=true, stop=close, qty=entryQty) f_showEntryInfo(true) if shouldMakeEntryShort strategy.entry(id="Short", long=false, stop=close, qty=entryQty) f_showEntryInfo(false) strategy.exit('Long-SL/TP', 'Long', stop=sl_long) strategy.exit('Short-SL/TP', 'Short', stop=sl_short) //============================================================================ // plot misc //============================================================================ sl = strategy.position_size > 0 ? sl_long : strategy.position_size < 0 ? sl_short : na plot(sl, color=color.red, style=plot.style_cross, linewidth=2, title="SL") value_bgcolor = rangeBreakDetected_long ? color.green : rangeBreakDetected_short ? color.red : COLOR_TRANSPARENT bgcolor(value_bgcolor, transp=95)