Log in to see Cloud of Tags

Wealth-Lab Wiki

TASC 2015-10 | The Money Flow Oscillator (Apirine)

RSS

Traders' Tip text

The Money Flow Oscillator (MFO) created by Vitali Apirine measures buying and selling pressure over a specific lookback. Bullish divergence indicates less selling pressure and bearish divergence indicates less buying pressure. Signals can be generated by looking for divergences of MFO with price and centerline crossovers. For our example code, we will combine both ideas into a counter-trend long-only trading system.

To identify divergences between price and oscillator, we'll be applying a straightforward approach. A divergence is detected when the SRSI indicator fails to confirm a price extreme, that is, the highest high of 20 days for bearish divergence or the 20-day lowest low for bullish divergence. This technique improves divergence detection time, practically reducing delay to a minimum compared to finding retracements from recent peaks or troughs.

System rules

  • Once a bullish divergence is detected, enter long next bar at open if MFO is below its centerline
  • Exit long next bar at open when MFO crosses above the centerline

Trades from the short side are deliberately not taken as their performance seems poor.

Image

Figure 1. Bullish divergence between the MFO and price formed in June 2015 triggered a long trade in KO (Coca Cola).

After updating the TASCIndicators library to v2015.09 or later, the MoneyFlowOscillator indicator can be found under the TASC Magazine Indicators group. You can plot it on a chart or use it as an entry or exit condition in a Rule-based Strategy without having to program a line of code yourself.

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
using TASCIndicators;

namespace WealthLab.Strategies { /* MFO divergence: Price sets a lowest low but the indicator fails to confirm the new low and turns up */ public class MFO_Divergence : WealthScript { private StrategyParameter paramHighest; private StrategyParameter paramPeriod; public MFO_Divergence() { paramPeriod = CreateParameter("MFO period", 20, 2, 100, 1); paramHighest = CreateParameter("Highest high of", 20, 5, 50, 1); } protected override void Execute() { bool peak = false; int peakBar = -1; int high = paramHighest.ValueInt; bool trough = false; int troughBar = -1; int low = paramHighest.ValueInt; int period = paramPeriod.ValueInt; MoneyFlowOscillator mfo = MoneyFlowOscillator.Series( Bars, period ); Lowest indicatorLowest = Lowest.Series( mfo, low ); Lowest hLow = Lowest.Series( Low, low ); HideVolume(); LineStyle solid = LineStyle.Solid; ChartPane mfoPane = CreatePane( 50, false, true ); PlotSeries( mfoPane, mfo, Color.Green, solid, 2 ); DrawHorzLine( mfoPane,0,Color.Blue,LineStyle.Dashed,1);

for(int bar = GetTradingLoopStartBar(period); bar < Bars.Count; bar++) { if (!IsLastPositionActive) { /* 1st peak: both price and indicator */ if( peak == false ) { if( ( High[bar-1] == Highest.Series( High, high )[bar-1] ) & ( mfo[bar-1] == Highest.Series( mfo, high )[bar-1] ) & TurnDown( bar, High ) & TurnDown( bar, mfo ) ) { peak = true; peakBar = bar-1; } } if( peak == true ) { if( ( High[bar] != Highest.Series( High, high )[bar] ) & ( mfo[bar] == Highest.Series( mfo, high )[bar] ) ) peak = false; }

/* 2nd peak: price high not confirmed by the indicator */

if( peak == true ) { if( ( High[bar-1] == Highest.Series( High, high )[bar-1] ) & ( High[bar-1] >= High[peakBar] ) & ( mfo[bar-1] != Highest.Series( mfo, high )[bar-1] ) & ( mfo[bar-1] < mfo[peakBar] ) & TurnDown( bar, High ) & TurnDown( bar, mfo ) ) { peak = false; /* Shorting doesn't work well */ // Fade the trend // if( mfo[bar] > 0 ) // if( ShortAtMarket( bar+1 ) != null ) // LastPosition.Priority = Close[bar]; /* Highlight divergence */ for (int b = peakBar; b <= bar; b++) SetPaneBackgroundColor( mfoPane, b, Color.FromArgb( 30, Color.LightCoral ) ); DrawLine( PricePane, peakBar, High[peakBar], bar-1, High[bar-1], Color.Red, solid, 2 ); DrawLine( mfoPane, peakBar, mfo[peakBar], bar-1, mfo[bar-1], Color.Blue, solid, 2 ); } }

/* 1st trough: both price and indicator */ if( trough == false ) { if( ( Low[bar-1] == Lowest.Series( Low, low )[bar-1] ) & ( mfo[bar-1] == Lowest.Series( mfo, low )[bar-1] ) & TurnUp( bar, Low ) & TurnUp( bar, mfo ) ) { trough = true; troughBar = bar-1; } } if( trough == true ) { if( ( Low[bar] != Lowest.Series( Low, low )[bar] ) & ( mfo[bar] == Lowest.Series( mfo, low )[bar] ) ) trough = false; }

/* 2nd trough: price low not confirmed by the indicator */

if( trough == true ) { if( ( Low[bar-1] == Lowest.Series( Low, low )[bar-1] ) & ( Low[bar-1] <= Low[troughBar] ) & ( mfo[bar-1] != Lowest.Series( mfo, low )[bar-1] ) & ( mfo[bar-1] > mfo[troughBar] ) & TurnUp( bar, Low ) & TurnUp( bar, mfo ) ) { trough = false; /* Fade the trend */

if( mfo[bar] < 0 ) if( BuyAtMarket( bar+1 ) != null ) LastPosition.Priority = -Close[bar]; /* Highlight divergence */ for (int b = troughBar; b <= bar; b++) SetPaneBackgroundColor( mfoPane, b, Color.FromArgb( 30, Color.LightGreen ) ); DrawLine( PricePane, troughBar, Low[troughBar], bar-1, Low[bar-1], Color.Blue, solid, 2 ); DrawLine( mfoPane, troughBar, mfo[troughBar], bar-1, mfo[bar-1], Color.Red, solid, 2 ); } } } else { Position p = LastPosition;

if( p.PositionType == PositionType.Long ) { if( CrossOver(bar, mfo, 0) ) ExitAtMarket( bar+1, p, "MFO Crossover" ); } else if( CrossUnder(bar, mfo, 0) ) ExitAtMarket( bar+1, p, "MFO Crossunder" ); } } } } }

Eugene
Wealth-Lab team
www.wealth-lab.com

Important Disclaimer: The information provided by Wealth-Lab is strictly for informational purposes and is not to be construed as advice or solicitation to buy or sell any security.  The owner of Wealth-Lab.com assumes no liability resulting from the use of the material contained herein for investment purposes. By using this web site, you agree to the terms of this disclaimer and our Terms of Use.


ScrewTurn Wiki. Some of the icons created by FamFamFam.