public Trade(ISavedTrade savedTrade) { StrategyEntryLevel = savedTrade.StrategyEntryLevel; StopLevel = savedTrade.StopLevel; Target = savedTrade.Target; OpenLevel = savedTrade.OpenLevel; Direction = Target > StopLevel ? TradeDirection.Long : TradeDirection.Short; CloseLevel = savedTrade.CloseLevel == -1 ? Option.None <double>() : Option.Some(savedTrade.CloseLevel); OpenTime = savedTrade.OpenTime; CloseTime = savedTrade.CloseTime == DateTime.MinValue ? Option.None <DateTime>() : Option.Some(savedTrade.CloseTime); Size = savedTrade.Size; MaximumAdverseExcursionPoints = savedTrade.MaximumAdverseExcursion == -1 ? Option.None <double>() : Option.Some(savedTrade.MaximumAdverseExcursion); MaximumFavourableExcursionPoints = savedTrade.MaximumFavourableExcursion == -1 ? Option.None <double>() : Option.Some(savedTrade.MaximumFavourableExcursion); CalculateResult(); }
private void UpdateGapFilledFlags() { for (var i = 0; i < DailyCandles.Count; i++) { if (DailyCandles[i].Gap.GapFillPercentage == 100) { DailyCandles[i].Gap.HasGapBeenFilled = true; DailyCandles[i].Gap.GapFillDate = Option.Some(DailyCandles[i].Date); } else { if (DailyCandles[i].Gap.GapPoints > 0) { for (var j = i + 1; j < DailyCandles.Count; j++) { if (DailyCandles[j].Low < DailyCandles[i].Open - DailyCandles[i].Gap.GapPoints) { DailyCandles[i].Gap.HasGapBeenFilled = true; DailyCandles[i].Gap.GapFillDate = Option.Some(DailyCandles[j].Date); break; } } } else { for (var j = i + 1; j < DailyCandles.Count; j++) { if (DailyCandles[j].High > DailyCandles[i].Open - DailyCandles[i].Gap.GapPoints) { DailyCandles[i].Gap.HasGapBeenFilled = true; DailyCandles[i].Gap.GapFillDate = Option.Some(DailyCandles[j].Date); break; } } } } if (!DailyCandles[i].Gap.HasGapBeenFilled) { UnfilledGaps.Add(DailyCandles[i].Gap); } } }
private void CalculateResult() { StopSize = Math.Abs(OpenLevel - StopLevel); RiskRewardRatio = Math.Abs(Target - StrategyEntryLevel) / StopSize; CloseLevel.IfExistsThen(x => { ResultInR = Option.Some(Math.Abs(x - OpenLevel) / StopSize); PointsProfit = Direction == TradeDirection.Long ? Option.Some(x - OpenLevel) : Option.Some(OpenLevel - x); }); MaximumAdverseExcursionPoints.IfExistsThen(x => { MaximumAdverseExcursionPercentageOfStop = Option.Some(x / StopSize); }); MaximumFavourableExcursionPoints.IfExistsThen(x => { PointsProfit.IfExistsThen(y => { if (y > 0) { PointsProfitPercentageOfMaximumFavourableExcursion = Option.Some(y / x); UnrealisedProfitPoints = Option.Some(x - y); } else { UnrealisedProfitPoints = Option.Some(x); } UnrealisedProfitPoints.IfExistsThen(z => { UnrealisedProfitCash = Option.Some(z * Size); }); }); }); PointsProfit.IfExistsThen(x => { CashProfit = Option.Some(Size * x); }); }
public Optional <string> OpenSaveDialog(object sender, string fileName, string filter) { var result = Option.None <string>(); _context.Send(_ => { var saveFileDialog = new SaveFileDialog { Filter = filter, Title = "Save Data", FileName = fileName }; if (saveFileDialog.ShowDialog() != false) { result = Option.Some(saveFileDialog.FileName); } }); return(result); }
internal static Optional <ITrade> AttemptTrade(IEnumerable <BidAskCandle> candles, double entry, double stop, double target, TimeSpan startTime, TimeSpan endTime, double risk, bool trialStop, double trialedStopSize) { var executed = false; var openTime = DateTime.MaxValue; var lastCandle = new BidAskCandle(new DateTime(1, 1, 1), 1, 1, 1, 1, 1, Timezone.Uk); double openLevel = 0; var stopSize = Math.Abs(entry - stop); var positionSize = risk / stopSize; var direction = target > stop ? TradeDirection.Long : TradeDirection.Short; var high = double.NegativeInfinity; var low = double.PositiveInfinity; var originalStop = stop; var maximumAdverseExcursion = 0.0; var maximumFavourableExcursion = 0.0; var stopTrailed = false; foreach (var candle in candles) { if (candle.DateTime.TimeOfDay >= startTime && candle.DateTime.TimeOfDay <= endTime) { if (direction == TradeDirection.Long) { if (trialStop && executed) { if (candle.BidOpen > high) { high = candle.BidOpen; } // Trail stop only if in profit by at least the size of the trailed stop if (high > stop + trialedStopSize && high > openLevel + trialedStopSize) { stop = candle.BidOpen - trialedStopSize; stopTrailed = true; } } // When not starting at the first candle of the day, // if the first candle opens past the initial intended entry (positive slippage), // enter the trade on the open of that candle and update stop level accordingly if (candle.AskOpen <= entry && !executed) { openLevel = candle.AskOpen; stop = openLevel - stopSize; originalStop = openLevel - stopSize; executed = true; openTime = candle.DateTime; } if (candle.AskLow < entry && !executed) { openLevel = entry; executed = true; openTime = candle.DateTime; } if (executed) { var adverseExcursion = openLevel - candle.AskLow; if (adverseExcursion > maximumAdverseExcursion) { maximumAdverseExcursion = adverseExcursion; } var favourableExcursion = candle.BidHigh - openLevel; if (favourableExcursion > maximumAdverseExcursion) { maximumFavourableExcursion = favourableExcursion; } // Ensure MFA is 100% if target is hit if (candle.BidHigh > target) { maximumFavourableExcursion = target - openLevel; } } if (candle.BidLow < stop && executed) { // Ensure MAE is 100% if full original stop is hit if (!stopTrailed) { maximumAdverseExcursion = stopSize; } return(Option.Some((ITrade) new Trade(entry, originalStop, target, openLevel, Option.Some(stop), openTime, Option.Some(candle.DateTime), positionSize, Option.Some(maximumAdverseExcursion), Option.Some(maximumFavourableExcursion)))); } if (candle.BidHigh > target && executed) { return(Option.Some((ITrade) new Trade(entry, originalStop, target, openLevel, Option.Some(target), openTime, Option.Some(candle.DateTime), positionSize, Option.Some(maximumAdverseExcursion), Option.Some(maximumFavourableExcursion)))); } } else if (direction == TradeDirection.Short) { if (trialStop && executed) { if (candle.AskOpen < low) { low = candle.AskOpen; } if (low < stop - trialedStopSize && low < openLevel - trialedStopSize) { stop = candle.AskOpen + trialedStopSize; stopTrailed = true; } } // See above comment on opposite direction trade if (candle.BidOpen >= entry && !executed) { openLevel = candle.BidOpen; stop = openLevel + stopSize; originalStop = openLevel + stopSize; executed = true; openTime = candle.DateTime; } if (candle.BidHigh > entry && !executed) { openLevel = entry; executed = true; openTime = candle.DateTime; } if (executed) { var adverseExcursion = candle.BidHigh - openLevel; if (adverseExcursion > maximumAdverseExcursion) { maximumAdverseExcursion = adverseExcursion; } var favourableExcursion = openLevel - candle.AskLow; if (favourableExcursion > maximumAdverseExcursion) { maximumFavourableExcursion = favourableExcursion; } // Ensure MFA is 100% if target is hit if (candle.AskLow < target) { maximumFavourableExcursion = openLevel - target; } } if (candle.AskHigh > stop && executed) { // Ensure MAE is 100% if full original stop is hit if (!stopTrailed) { maximumAdverseExcursion = stopSize; } return(Option.Some((ITrade) new Trade(entry, originalStop, target, openLevel, Option.Some(stop), openTime, Option.Some(candle.DateTime), positionSize, Option.Some(maximumAdverseExcursion), Option.Some(maximumFavourableExcursion)))); } if (candle.AskLow < target && executed) { return(Option.Some((ITrade) new Trade(entry, originalStop, target, openLevel, Option.Some(target), openTime, Option.Some(candle.DateTime), positionSize, Option.Some(maximumAdverseExcursion), Option.Some(maximumFavourableExcursion)))); } } lastCandle = candle; } } if (!executed) { return(Option.None <ITrade>()); } // When trade is executed but neither stop or target is hit close trade at close level of last candle double close; close = direction == TradeDirection.Long ? lastCandle.BidClose : lastCandle.AskClose; return(Option.Some((ITrade) new Trade(entry, originalStop, target, entry, Option.Some(close), openTime, Option.Some(lastCandle.DateTime), positionSize, Option.Some(maximumAdverseExcursion), Option.Some(maximumFavourableExcursion)))); }