//============================================================================ // Author : Ray Burkholder, ray@oneunified.net // Copyright : (c) 2007 One Unified // License : Released under GPL3 // Status : No warranty, express or implied. Supplied as is. // Note : Please contact author for commercial use rights // Date : 2007/10/07 // First File : 2006/01/10 //============================================================================ using System; using System.ComponentModel; using System.Drawing; using System.Collections; using SmartQuant.Data; using SmartQuant.Series; using SmartQuant.Indicators; using SmartQuant.Instruments; using SmartQuant.Trading; using SmartQuant.Optimization; namespace OneUnified { public class Candle: Object { public const double bald = 0.02; // 2 cents public enum ETrend { Yin, // bearish Yang, // bullish Neutral } public enum ETradingDay { Long, // > average body Short, // < 40% of average body, Neutral // anything else } public enum ECandle { BlackMarubozu, // yin, no shadows, a weak indicator // identified in bearish continuation, // or bullish reversal particularily if during a downtrend WhiteMarubozu, // yang, no shadows, extremely strong pattern // usually first part of bullish continuation, or bearish reversal ClosingBlackMarubozu, // no shadow on closing end // strong bearish signal ClosingWhiteMarubozu, // no shadow on closing end // strong bullish signal OpeningBlackMarubozu, // no shadow on opening end // strong bearish signal, not as strong as closing one OpeningWhiteMarubozu, // no shadow on opening end // strong bullish signal, not as strong as closing one SpinningTop, // small bodies relative to the shadows // neutral in sideways market, // in trending market, next day will move in direction of opening price Doji, // open and close are same or very nearly same // longer the shadow(s), the more important // very important signal DojiStar, // open close near mid point GravestoneDoji, // best as a bottom reversal, long hair DragonflyDoji, // long tail Unknown // unclassified } public Candle() { } public static ETrend Direction( Bar bar ) { ETrend e = ETrend.Neutral; if ( Math.Abs( bar.Close - bar.Open ) <= bald ) { e = ETrend.Neutral; } else { if ( bar.Close > bar.Open ) { e = ETrend.Yang; } else { e = ETrend.Yin; } } return e; } public static ETradingDay TradingDayType( Bar bar, double avgBody ) { ETradingDay td = ETradingDay.Neutral; if ( Body( bar ) > ( 1.1 * avgBody ) ) { td = ETradingDay.Long; } else { if ( Body( bar ) < ( 0.40 * avgBody ) ) td = ETradingDay.Short; } return td; } public static double Body( Bar bar ) { // body is difference between open and close return Math.Abs( bar.Close - bar.Open ); } // Hair and Tail are also called top and bottom shadows public static double Hair( Bar bar ) { // hair is amount above body return bar.High - Math.Max( bar.Open, bar.Close ); } public static double Tail( Bar bar ) { // tail is amount below body return Math.Min( bar.Open, bar.Close ) - bar.Low; } public static double Total( Bar bar ) { return bar.High - bar.Low; } public static bool isHammer( Bar bar, double avgBody ) { return ( ( Tail( bar ) > ( 2.0 * Body( bar ) ) ) && ( Hair( bar ) <= bald ) ); } public static bool isHangingMan( Bar bar, double avgBody ) { return isHammer( bar, avgBody ); } public static bool isReverseHammer( Bar bar, double avgBody ) { return ( ( Hair( bar ) > ( 2.0 * Body( bar ) ) ) && ( Tail( bar ) <= bald ) ); } public static bool isShootingStar( Bar bar, double avgBody ) { return isReverseHammer( bar, avgBody ); } public static bool isSmallBody( Bar bar, double avgBody ) { return ( ( Body( bar ) < ( 0.30 * avgBody ) ) ); } public static bool isBlackLong( Bar bar, double avgBody ) { return ( ( ETradingDay.Long == TradingDayType( bar, avgBody ) ) && ( ETrend.Yin == Direction( bar ) ) ); } public static bool isWhiteLong( Bar bar, double avgBody ) { return ( ( ETradingDay.Long == TradingDayType( bar, avgBody ) ) && ( ETrend.Yang == Direction( bar ) ) ); } public static bool isBlackMarubozu( Bar bar, double avgBody ) { return ( ( ETradingDay.Long == TradingDayType( bar, avgBody ) ) && ( ETrend.Yin == Direction( bar ) ) && ( bald >= Hair( bar ) ) // no hair && ( bald >= Tail( bar ) ) // no tail ); } public static bool isWhiteMarubozu( Bar bar, double avgBody ) { return ( ( ETradingDay.Long == TradingDayType( bar, avgBody ) ) && ( ETrend.Yang == Direction( bar ) ) && ( bald >= Hair( bar ) ) // no hair && ( bald >= Tail( bar ) ) // no tail ); } public static bool isClosingBlackMarubozu( Bar bar, double avgBody ) { return ( ( ETradingDay.Long == TradingDayType( bar, avgBody ) ) && ( ETrend.Yin == Direction( bar ) ) //&& ( bald <= Hair( bar ) ) // has hair (doesn't matter) && ( bald >= Tail( bar ) ) // no tail ); } public static bool isClosingWhiteMarubozu( Bar bar, double avgBody ) { return ( ( ETradingDay.Long == TradingDayType( bar, avgBody ) ) && ( ETrend.Yang == Direction( bar ) ) && ( bald >= Hair( bar ) ) // no hair //&& ( bald <= Tail( bar ) ) // has tail (doesn't matter) ); } public static bool isOpeningBlackMarubozu( Bar bar, double avgBody ) { return ( ( ETradingDay.Long == TradingDayType( bar, avgBody ) ) && ( ETrend.Yin == Direction( bar ) ) && ( bald >= Hair( bar ) ) // no hair //&& ( bald <= Tail( bar ) ) // has tail (doesn't matter) ); } public static bool isOpeningWhiteMarubozu( Bar bar, double avgBody ) { return ( ( ETradingDay.Long == TradingDayType( bar, avgBody ) ) && ( ETrend.Yang == Direction( bar ) ) //&& ( bald <= Hair( bar ) ) // has hair (doesn't matter) && ( bald >= Tail( bar ) ) // no tail ); } public static bool isSpinningTop( Bar bar, double avgBody ) { return ( ( ( ( bar.High - bar.Low ) * 0.50 ) > Body( bar ) ) && ( Tail( bar ) > ( ( bar.High - bar.Low ) * 0.10 ) ) && ( Hair( bar ) > ( ( bar.High - bar.Low ) * 0.10 ) ) ); } public static bool isDoji( Bar bar, double avgBody ) { return ( Body( bar ) <= Candle.bald // may need to make sure it has shadows on both ends ); } public static bool isDojiStar( Bar bar, double avgBody ) { return ( isDoji( bar, avgBody ) && ( ( Math.Abs( Hair( bar ) - Tail( bar ) ) / Total( bar ) ) < 0.50 ) ); } public static bool isGravestoneDoji( Bar bar, double avgBody ) { return ( isDoji( bar, avgBody ) && ( ( Tail( bar ) / Total( bar ) ) < 0.04 ) ); } public static bool isDragonflyDoji( Bar bar, double avgBody ) { return ( isDoji( bar, avgBody ) && ( ( Hair( bar ) / Total( bar ) ) < 0.04 ) ); } } }