The Open Close Cross Moving Average Trend Following Strategy is a trend following strategy based on moving averages of the open and close prices. It determines the current market trend by calculating the moving averages of the open and close prices; it goes long when the closing price moving average crosses above the opening price moving average, and goes short when the closing price moving average crosses below the opening price moving average. The strategy also sets trailing stops to lock in profits and effectively control risks.
The core logic of this strategy is based on the relationship between the open and close prices to determine the current trend. The opening price reflects the current market supply-demand relationship and trading psychology, while the closing price reflects the final traded outcome of the day. In general, if the closing price is higher than the opening price, it indicates that the market trend for the day is upward and sentiment is more bullish. If the closing price is lower than the opening price, it suggests the market trend for the day is downward and sentiment is more bearish.
This strategy utilizes this logic by calculating the moving averages of the open and close prices to judge the current trend direction. Specifically, its trading rules are:
Go long when the closing price moving average crosses above the opening price moving average. This signals that bullish sentiment is strengthening and a long position can be initiated.
Go short when the closing price moving average crosses below the opening price moving average. This suggests that bearish sentiment is rising and a short position can be initiated.
Close existing positions with a stop loss when reverse signals happen.
The strategy also sets trailing stops to lock in profits. After entering a position, it dynamically calculates the point difference between the entry price and the current price. When the price movement exceeds the set stop loss point threshold, the stop loss line will move up to lock in partial profits.
In summary, the strategy judges trends over the moving average period length; holds only one directional position at a time; exits existing positions directly with reverse signals without ATR stops; and has trailing stop settings to lock in profits.
This strategy has the following main advantages:
Simple and Clear Rules. Judging trend based on open-close relationship is easy to understand and optimize parameters for.
Flexible MA Choices. There are dozens of MA types to choose from and optimize.
Adjustable Resolution. The resolution can be set to 3-4x of chart for more sensitivity and timeliness of signals.
Stop Loss Mechanism. The trailing stop effectively controls loss and drawdown per trade.
Customizable Holding Period. The holding period and volatility can be controlled by adjusting MA parameters.
Flexibly Tunable Risk-Reward. Stop loss points and offset fine tunes risk-reward preference.
The main risks of this strategy lie in the following areas:
Missing Trend Reversals. Exit signals may lag price reversals resulting in overholding losses. Shortening MA period can alleviate this.
Not Suitable for High Volatility Conditions. Frequent whipsaws under volatile conditions creates high commission costs. Widening stop loss points or lengthening MA period can help here.
Reliance on Single Indicator. Basing decisions on just one indicator set exposes it to failure risk. Adding other indicators like MACD could complement the logic.
Over-optimization Risk. MA parameters and stop loss settings can be easily overfit. Out-of-sample performance may deteriorate. Caution should be taken in parameter selection.
The strategy can be optimized and enhanced from areas like:
Complementary indicators. Volatility and momentum indicators can increase robustness and stability.
Conditional Dynamic Parameters. MA periods can be adjusted based on trending or sideways market regime detection for better adaptiveness.
Dynamic risk control. Stop loss points and offsets can be calibrated on recent realized volatility levels.
Enhanced Stop Loss Logic. More advanced stop loss mechanisms like ATR stops can replace the simplistic trailing stop.
The Open Close Cross Moving Average Trend Following Strategy is a typical trend trading strategy based on open-close relationship and moving averages. Its advantages like simple rules, flexibility and controllable risks also comes with drawbacks of missing reversals and whipsaws. Enhancement areas include more indicators, dynamic parameters, and advanced risk management for better trend catches and adaptability to varying market conditions.
/*backtest start: 2023-01-08 00:00:00 end: 2024-01-14 00:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=4 strategy(title = "Open Close Cross Strategy (PineScript=v4)", shorttitle = "OCC Strategy", overlay = true ) // Revision: 1 // Author: @JayRogers // // Description: // - Strategy based around Open-Close Crossovers. // Setup: // - I have generally found that setting the strategy resolution to 3-4x that of the chart you are viewing // tends to yield the best results, regardless of which MA option you may choose (if any) // - Don't aim for perfection. Just aim to get a reasonably snug fit with the O-C band, with good runs of // green and red. // - Option to either use basic open and close series data, or pick your poison with a wide array of MA types. // - Optional trailing stop for damage mitigation if desired (can be toggled on/off) // - Positions get taken automagically following a crossover - which is why it's better to set the resolution // of the script greater than that of your chart, so that the trades get taken sooner rather than later. // - If you make use of the trailing stops, be sure to take your time tweaking the values. Cutting it too fine // will cost you profits but keep you safer, while letting them loose could lead to more drawdown than you // can handle. // === INPUTS === useRes = input(defval=true, title="Use Alternate Resolution? ( recommended )") stratRes = input(defval="120", title="Set Resolution ( should not be lower than chart )", type=input.resolution) useMA = input(defval=true, title="Use MA? ( otherwise use simple Open/Close data )") basisType = input(defval="DEMA", title="MA Type: SMA, EMA, DEMA, TEMA, WMA, VWMA, SMMA, HullMA, LSMA, ALMA ( case sensitive )", type=input.string) basisLen = input(defval=14, title="MA Period", minval=1) offsetSigma = input(defval=6, title="Offset for LSMA / Sigma for ALMA", minval=0) offsetALMA = input(defval=0.85, title="Offset for ALMA", minval=0, step=0.01) useStop = input(defval=true, title="Use Trailing Stop?") slPoints = input(defval=200, title="Stop Loss Trail Points", minval=1) slOffset = input(defval=400, title="Stop Loss Trail Offset", minval=1) // === /INPUTS === // === BASE FUNCTIONS === // Returns MA input selection variant, default to SMA if blank or typo. variant(type, src, len, offSig, offALMA) => v1 = sma(src, len) // Simple v2 = ema(src, len) // Exponential v3 = 2 * v2 - ema(v2, len) // Double Exponential v4 = 3 * (v2 - ema(v2, len)) + ema(ema(v2, len), len) // Triple Exponential v5 = wma(src, len) // Weighted v6 = vwma(src, len) // Volume Weighted sma_1 = sma(src, len) // Smoothed v7 = na(v5[1]) ? sma_1 : (v5[1] * (len - 1) + src) / len v8 = wma(2 * wma(src, len / 2) - wma(src, len), round(sqrt(len))) // Hull v9 = linreg(src, len, offSig) // Least Squares v10 = alma(src, len, offALMA, offSig) // Arnaud Legoux type == "EMA" ? v2 : type == "DEMA" ? v3 : type == "TEMA" ? v4 : type == "WMA" ? v5 : type == "VWMA" ? v6 : type == "SMMA" ? v7 : type == "HullMA" ? v8 : type == "LSMA" ? v9 : type == "ALMA" ? v10 : v1 // security wrapper for repeat calls reso(exp, use, res) => security_1 = security(syminfo.tickerid, res, exp) use ? security_1 : exp // === /BASE FUNCTIONS === // === SERIES SETUP === // open/close variant__1 = variant(basisType, close, basisLen, offsetSigma, offsetALMA) reso__1 = reso(variant__1, useRes, stratRes) reso__2 = reso(close, useRes, stratRes) closeSeries = useMA ? reso__1 : reso__2 variant__2 = variant(basisType, open, basisLen, offsetSigma, offsetALMA) reso__3 = reso(variant__2, useRes, stratRes) reso__4 = reso(open, useRes, stratRes) openSeries = useMA ? reso__3 : reso__4 trendState = bool(na) trendState := closeSeries > openSeries ? true : closeSeries < openSeries ? false : trendState[1] // === /SERIES === // === PLOTTING === barcolor(color=closeSeries > openSeries ? #006600 : #990000, title="Bar Colours") // channel outline closePlot = plot(closeSeries, title="Close Line", color=#009900, linewidth=2, style=plot.style_line, transp=90) openPlot = plot(openSeries, title="Open Line", color=#CC0000, linewidth=2, style=plot.style_line, transp=90) // channel fill closePlotU = plot(trendState ? closeSeries : na, transp=100, editable=false) openPlotU = plot(trendState ? openSeries : na, transp=100, editable=false) closePlotD = plot(trendState ? na : closeSeries, transp=100, editable=false) openPlotD = plot(trendState ? na : openSeries, transp=100, editable=false) fill(openPlotU, closePlotU, title="Up Trend Fill", color=#009900, transp=40) fill(openPlotD, closePlotD, title="Down Trend Fill", color=#CC0000, transp=40) // === /PLOTTING === // === STRATEGY === // conditions longCond = crossover(closeSeries, openSeries) shortCond = crossunder(closeSeries, openSeries) // entries and base exit strategy.entry("long", strategy.long, when=longCond) strategy.entry("short", strategy.short, when=shortCond) // if we're using the trailing stop if useStop strategy.exit("XL", from_entry="long", trail_points=slPoints, trail_offset=slOffset) strategy.exit("XS", from_entry="short", trail_points=slPoints, trail_offset=slOffset) // not sure needed, but just incase.. strategy.exit("XL", from_entry="long", when=shortCond) strategy.exit("XS", from_entry="short", when=longCond) // === /STRATEGY ===