예제 #1
0
        public static PriceBar GetContainingBar(PriceBar smallerPriceBar, List <PriceBar> largerPriceBars)
        {
            PriceBarSize smallerBarType = smallerPriceBar.BarSize;
            PriceBarSize largerBarSize  = largerPriceBars.FirstOrDefault().BarSize;

            if (smallerBarType.ToInt() > largerBarSize.ToInt())
            {
                throw new UnknownErrorException();
            }

            // Convert the smaller bar date time to the start date of the larger bar
            switch (largerBarSize)
            {
            case PriceBarSize.Daily:
                return(smallerPriceBar);

            case PriceBarSize.Weekly:
                var newWeekDate = Calendar.FirstTradingDayOfWeek(smallerPriceBar.BarDateTime);
                return(largerPriceBars.SingleOrDefault(x => x.BarDateTime == newWeekDate));

            case PriceBarSize.Monthly:
                var newMonthDate = Calendar.FirstTradingDayOfMonth(smallerPriceBar.BarDateTime);
                return(largerPriceBars.SingleOrDefault(x => x.BarDateTime == newMonthDate));

            case PriceBarSize.Quarterly:
                var newQuarterDate = Calendar.FirstTradingDayOfQuarter(smallerPriceBar.BarDateTime);
                return(largerPriceBars.SingleOrDefault(x => x.BarDateTime == newQuarterDate));

            default:
                break;
            }
            return(null);
        }
예제 #2
0
 /// <summary>
 /// Returns PriceBar values as High-Low-Open-Close for use in a Candlestick charting element
 /// </summary>
 /// <param name="bar"></param>
 /// <returns></returns>
 public static double[] AsChartingValue(this PriceBar bar)
 {
     return(new double[]
     {
         bar.High.ToDouble(),
         bar.Low.ToDouble(),
         bar.Open.ToDouble(),
         bar.Close.ToDouble()
     });
 }
예제 #3
0
            public void AddValues(PriceBar firstBarOfTrend, PriceBar lastBarOfTrend)
            {
                if (firstBarOfTrend.Open == 0)
                {
                    return;
                }

                var changePercent = (lastBarOfTrend.Close - firstBarOfTrend.Open) / firstBarOfTrend.Open;

                AverageChange = ((AverageChange * NumberOccurrance) + changePercent) / ++NumberOccurrance;
            }
예제 #4
0
        protected override bool Rule(Trade trade, Portfolio portfolio, DateTime AsOf, TimeOfDay timeOfDay)
        {
            PriceBar bar = trade.Security.GetPriceBar(AsOf, PriceBarSize.Daily);
            decimal  atr = bar.AverageTrueRange(Stoploss_Atr_Period);

            if (bar.Close - (atr * Stoploss_Multiple) < 0)
            {
                return(false);
            }

            return(true);
        }
예제 #5
0
        private static void Candlestick_Hammer(this PriceBar me)
        {
            decimal wickToBody     = 2.0m;
            decimal upperWickLimit = .25m;

            // Bottom of a down trend, with a lower wick at least 2x body, closing at or near high

            // Define downtrend using SP bar count
            var priorBars = me.PriorBars(3, false);

            if (priorBars.Count < 3)
            {
                me.SetCandlestickFlag(CandleStickPattern.BullishHammer, false);
                return;
            }

            if (priorBars.Min(x => x.Low) <= Math.Min(me.Open, me.Close))
            {
                me.SetCandlestickFlag(CandleStickPattern.BullishHammer, false);
                return;
            }

            var lowerWick = Math.Min(me.Open, me.Close) - me.Low;
            var upperWick = me.High - Math.Max(me.Open, me.Close);
            var body      = Math.Abs(me.Change);

            if (lowerWick < 0)
            {
                me.SetCandlestickFlag(CandleStickPattern.BullishHammer, false);
                return;
            }
            if (body > 0 && lowerWick / body < wickToBody)
            {
                me.SetCandlestickFlag(CandleStickPattern.BullishHammer, false);
                return;
            }
            if (lowerWick < me.AverageTrueRange())
            {
                me.SetCandlestickFlag(CandleStickPattern.BullishHammer, false);
                return;
            }
            if (upperWick > body * upperWickLimit)
            {
                me.SetCandlestickFlag(CandleStickPattern.BullishHammer, false);
                return;
            }

            me.SetCandlestickFlag(CandleStickPattern.BullishHammer, true);
            return;
        }
예제 #6
0
        private static void Technical_Volume(this PriceBar me)
        {
            if (me.PriorBar == null)
            {
                return;
            }

            if (me.Volume > me.PriorBar.Volume)
            {
                me.SetTechnicalFlag(Technical.RisingVolume, true);
            }
            else if (me.Volume < me.PriorBar.Volume)
            {
                me.SetTechnicalFlag(Technical.FallingVolume, true);
            }
        }
예제 #7
0
        protected void TryExecuteMarketTrade(Trade trade, DateTime AsOf)
        {
            if (trade.TradeType != TradeType.Market)
            {
                throw new InvalidTradeOperationException()
                      {
                          message = "Must provide Market type trade"
                      }
            }
            ;

            PriceBar usedPriceBar = trade.Security.GetPriceBar(AsOf, PriceBarSize.Daily);

            if (usedPriceBar == null)
            {
                throw new InvalidTradingDateException()
                      {
                          message = "Could not retrieve execution price bar"
                      }
            }
            ;

            ExecuteTrade(trade, usedPriceBar.Open, AsOf);
        }
예제 #8
0
        protected bool TryExecuteLimitTrade(Trade trade, DateTime AsOf, TimeOfDay timeOfDay)
        {
            if (trade.TradeType != TradeType.Limit)
            {
                throw new InvalidTradeOperationException()
                      {
                          message = "Must provide Limit type trade"
                      }
            }
            ;

            PriceBar usedPriceBar = trade.Security.GetPriceBar(AsOf, PriceBarSize.Daily);

            if (usedPriceBar == null)
            {
                throw new InvalidTradingDateException()
                      {
                          message = "Could not retrieve execution price bar"
                      }
            }
            ;

            switch (timeOfDay)
            {
            case TimeOfDay.MarketOpen:
            {
                switch (trade.TradeActionBuySell)
                {
                case TradeActionBuySell.None:
                    throw new InvalidTradeOperationException();

                case TradeActionBuySell.Buy:
                    if (usedPriceBar.Open <= trade.LimitPrice)
                    {
                        ExecuteTrade(trade, usedPriceBar.Open, AsOf);
                    }
                    return(true);

                case TradeActionBuySell.Sell:
                    if (usedPriceBar.Open >= trade.LimitPrice)
                    {
                        ExecuteTrade(trade, usedPriceBar.Open, AsOf);
                    }
                    return(true);
                }
            }
                return(false);

            case TimeOfDay.MarketEndOfDay:
            {
                switch (trade.TradeActionBuySell)
                {
                case TradeActionBuySell.None:
                    throw new InvalidTradeOperationException();

                case TradeActionBuySell.Buy:
                    if (usedPriceBar.Low <= trade.LimitPrice)
                    {
                        ExecuteTrade(trade, trade.LimitPrice, AsOf);
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }

                case TradeActionBuySell.Sell:
                    if (usedPriceBar.High >= trade.LimitPrice)
                    {
                        ExecuteTrade(trade, trade.LimitPrice, AsOf);
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
                return(false);

            default:
                return(false);
            }
        }
예제 #9
0
        protected void TryExecuteStopTrade(Trade trade, DateTime AsOf, TimeOfDay timeOfDay)
        {
            if (trade.Security.Ticker == "ACER" && AsOf == new DateTime(2018, 7, 31))
            {
                Console.WriteLine();
            }

            if (trade.TradeType != TradeType.Stop)
            {
                throw new InvalidTradeOperationException()
                      {
                          message = "Must provide Stop type trade"
                      }
            }
            ;

            PriceBar usedPriceBar = trade.Security.GetPriceBar(AsOf, PriceBarSize.Daily);

            if (usedPriceBar == null)
            {
                Logger.Log(new LogMessage(ToString() + ".TryExecuteStopTrade", $"Execution Error: no data for {trade.Security.Ticker} on {AsOf.ToShortDateString()}", LogMessageType.SecurityError));
                return;
            }

            switch (timeOfDay)
            {
            case TimeOfDay.MarketOpen:
            {
                switch (trade.TradeActionBuySell)
                {
                case TradeActionBuySell.None:
                    throw new InvalidTradeOperationException();

                case TradeActionBuySell.Buy:
                    if (usedPriceBar.Open >= trade.StopPrice)
                    {
                        ExecuteTrade(trade, usedPriceBar.Open, AsOf);
                    }
                    break;

                case TradeActionBuySell.Sell:
                    if (usedPriceBar.Open <= trade.StopPrice)
                    {
                        ExecuteTrade(trade, usedPriceBar.Open, AsOf);
                    }
                    break;
                }
            }
            break;

            case TimeOfDay.MarketEndOfDay:
            {
                switch (trade.TradeActionBuySell)
                {
                case TradeActionBuySell.None:
                    throw new InvalidTradeOperationException();

                case TradeActionBuySell.Buy:
                    if (usedPriceBar.High >= trade.StopPrice && trade.StopPrice.IsBetween(usedPriceBar.Low, usedPriceBar.High))
                    {
                        ExecuteTrade(trade, trade.StopPrice, AsOf);
                    }
                    break;

                case TradeActionBuySell.Sell:
                    if (usedPriceBar.Low <= trade.StopPrice && trade.StopPrice.IsBetween(usedPriceBar.Low, usedPriceBar.High))
                    {
                        ExecuteTrade(trade, trade.StopPrice, AsOf);
                    }
                    break;
                }
            }
            break;
            }
        }
예제 #10
0
        public static List <NetChangeByTrendType> GetNetChangeByTrendType(this Security me, PriceBarSize priceBarSize, int barCount, DateTime?start = null, DateTime?end = null)
        {
            List <PriceBar> PriceBarsUsed;

            switch (priceBarSize)
            {
            case PriceBarSize.Weekly:
            {
                PriceBarsUsed = me.WeeklyPriceBarData;
                if (!start.HasValue)
                {
                    start = me.GetFirstBar(PriceBarSize.Weekly).BarDateTime;
                    end   = me.GetLastBar(PriceBarSize.Weekly).BarDateTime;
                }
                if (start.HasValue && !end.HasValue)
                {
                    throw new UnknownErrorException()
                          {
                              message = "Invalid input dates"
                          }
                }
                ;
                start = FirstTradingDayOfWeek(start.Value);
                end   = FirstTradingDayOfWeek(end.Value);
            }
            break;

            case PriceBarSize.Monthly:
            {
                PriceBarsUsed = me.MonthlyPriceBarData;
                if (!start.HasValue)
                {
                    start = me.GetFirstBar(PriceBarSize.Monthly).BarDateTime;
                    end   = me.GetLastBar(PriceBarSize.Monthly).BarDateTime;
                }
                if (start.HasValue && !end.HasValue)
                {
                    throw new UnknownErrorException()
                          {
                              message = "Invalid input dates"
                          }
                }
                ;
                start = FirstTradingDayOfMonth(start.Value);
                end   = FirstTradingDayOfMonth(end.Value);
            }
            break;

            case PriceBarSize.Quarterly:
            {
                PriceBarsUsed = me.QuarterlyPriceBarData;
                if (!start.HasValue)
                {
                    start = me.GetFirstBar(PriceBarSize.Quarterly).BarDateTime;
                    end   = me.GetLastBar(PriceBarSize.Quarterly).BarDateTime;
                }
                if (start.HasValue && !end.HasValue)
                {
                    throw new UnknownErrorException()
                          {
                              message = "Invalid input dates"
                          }
                }
                ;
                start = FirstTradingDayOfQuarter(start.Value);
                end   = FirstTradingDayOfQuarter(end.Value);
            }
            break;

            case PriceBarSize.Daily:
            default:
            {
                PriceBarsUsed = me.DailyPriceBarData;
                if (!start.HasValue)
                {
                    start = me.GetFirstBar(PriceBarSize.Daily).BarDateTime;
                    end   = me.GetLastBar(PriceBarSize.Daily).BarDateTime;
                }
                if (start.HasValue && !end.HasValue)
                {
                    throw new UnknownErrorException()
                          {
                              message = "Invalid input dates"
                          }
                }
                ;
            }
            break;
            }


            if (PriceBarsUsed.Count == 0)
            {
                return(null);
            }

            // Create a return list of all trends except NotSet
            var ret = new List <NetChangeByTrendType>();

            foreach (var trend in Enum.GetValues(typeof(TrendQualification)))
            {
                if ((TrendQualification)trend != TrendQualification.NotSet)
                {
                    ret.Add(new Analysis.NetChangeByTrendType((TrendQualification)trend));
                }
            }

            // Set swingpoints and trends if not done already
            me.SetSwingPointsAndTrends(barCount, priceBarSize);

            // Get the first bar, ignore the starting ambilavent trend
            PriceBar currentBar = me.GetPriceBar(start.Value, priceBarSize);

            // Track the current trend as we go through each bar
            TrendQualification currentTrend = currentBar.GetTrendType(barCount);

            while (currentBar != null && currentBar.GetTrendType(barCount) == currentTrend)
            {
                currentBar = currentBar.NextBar;
            }

            PriceBar firstBarOfTrend = null;
            PriceBar lastBarOfTrend  = null;

            while (currentBar != null)
            {
                // Since the trend change is based on the ending value for a bar, we track a trend from the second instance through the first bar of the next trend
                if (currentTrend != currentBar.GetTrendType(barCount))
                {
                    lastBarOfTrend = currentBar;
                    if (firstBarOfTrend != null)
                    {
                        var trendResult = ret.Find(x => x.TrendType == currentTrend);
                        trendResult.AddValues(firstBarOfTrend, lastBarOfTrend);
                    }

                    firstBarOfTrend = currentBar.NextBar;
                    currentTrend    = currentBar.GetTrendType(barCount);
                }
                currentBar = currentBar.NextBar;
            }

            return(ret);
        }
예제 #11
0
        /// <summary>
        /// Positive value of overnight margin.  Calculated same as initial margin, but based on the closing day's value of the position
        /// </summary>
        /// <param name="position"></param>
        /// <param name="AsOf"></param>
        /// <returns>Positive value of maintenance margin</returns>
        public decimal BrokerMaintenanceMargin(Position position, DateTime AsOf, TimeOfDay MarketValues)
        {
            PriceBar currentBar = position.Security.GetPriceBar(AsOf, PriceBarSize.Daily);

            if (currentBar == null)
            {
                throw new InvalidTradingDateException()
                      {
                          message = "Could not retrieve price bar data"
                      }
            }
            ;

            switch (position.PositionDirection)
            {
            case PositionDirection.LongPosition:
            {
                var ret = (MaintenanceMarginLong * position.GrossPositionValue(AsOf, MarketValues));
                if (ret < 2000.0m)
                {
                    return(Math.Min(2000.0m, position.GrossPositionValue(AsOf, MarketValues)));
                }
                return(ret);
            }

            case PositionDirection.ShortPosition:
            {
                // From IBKR website: "All short transactions in margin accounts are subject to a minimum initial margin requirement of $2,000."
                var ValuePerShare = 0m;

                if (MarketValues == TimeOfDay.MarketOpen)
                {
                    ValuePerShare = currentBar.Open;
                }
                else if (MarketValues == TimeOfDay.MarketEndOfDay)
                {
                    ValuePerShare = currentBar.Close;
                }
                else
                {
                    throw new InvalidRequestValueException()
                          {
                              message = "MarketValues not set"
                          }
                };

                var Shares = Math.Abs(position.Size(AsOf));

                if (ValuePerShare <= 2.50m)
                {
                    // $2.50 per share or minimum of $2000.00
                    return(Math.Max((Shares * 2.50m), 2000.0m));
                }
                if (ValuePerShare <= 5.00m)
                {
                    // Market value of stock or minimum of $2000.00
                    return(Math.Max(Math.Abs(position.GrossPositionValue(AsOf, MarketValues)), 2000.0m));
                }
                if (ValuePerShare <= 16.67m)
                {
                    // $2.50 per share or minimum of $2000.00
                    return(Math.Max((Shares * 5.00m), 2000.0m));
                }
                else
                {
                    // Margin percentage requirement or minimum of $2000.00
                    return(Math.Max(MaintenanceMarginShort * Math.Abs(position.GrossPositionValue(AsOf, MarketValues)), 2000.0m));
                }
            }

            default:
            {
                throw new UnknownErrorException();
            }
            }
        }