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); }
/// <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() }); }
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; }
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); }
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; }
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); } }
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); }
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); } }
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; } }
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); }
/// <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(); } } }