/// <summary>Return the value of this order if it was to be closed at the given price tick</summary> public QuoteCurrency ValueAt(PriceTick price, bool consider_sl, bool consider_tp) { // Closing a Buy means selling to the highest *bid*er var p = TradeType == TradeType.Buy ? price.Bid : price.Ask; return(ValueAt(p, consider_sl, consider_tp)); }
///// <summary>Incorporate a candle into this trade</summary> //public void AddCandle(Candle candle) //{ // // Adding a candle "open"s an unknown trade // if (Result == EResult.Unknown) // Result = EResult.Open; // // If the trade is pending, look for an entry trigger // if (Result == EResult.LimitOrder) // { // if ((TradeType == TradeType.Buy && candle.Close >= EP) || // (TradeType == TradeType.Sell && candle.Close <= EP)) // { // Result = EResult.Open; // EntryIndex = candle.Index; // } // } // if (Result == EResult.StopEntryOrder) // { // } // // Trade has closed out // if (Result == EResult.HitSL || Result == EResult.HitTP) // return; // // Otherwise, if this is an open trade. // if (Result == EResult.Open) // { // // Assume the worst for order of prices within a candle // var prices = TradeType.Sign() > 0 // ? new[] {candle.Open, candle.Low, candle.High, candle.Close } // : new[] {candle.Open, candle.High, candle.Low, candle.Close }; // // Check each price value against the trade // var sign = TradeType.Sign(); // foreach (var p in prices) // { // // If the trade is a buy, then it closes at the bid price. // var price = sign > 0 ? (QuoteCurrency)p : p + Instrument.Spread; // // SL hit // if (SL != null && sign * (price - SL.Value) < 0) // { // NetProfit = sign * Instrument.Symbol.QuoteToAcct(SL.Value - EP) * Volume; // MaxAdverseExcursion = sign * (EP - SL.Value); // Result = EResult.HitSL; // Expiration = candle.TimestampUTC.DateTime; // break; // } // // TP hit // if (TP != null && sign * (price - TP.Value) > 0) // { // NetProfit = sign * Instrument.Symbol.QuoteToAcct(TP.Value - EP) * Volume; // MaxFavourableExcursion = sign * (TP.Value - EP); // Result = EResult.HitTP; // Expiration = candle.TimestampUTC.DateTime; // break; // } // // Update the current profit // NetProfit = sign * Instrument.Symbol.QuoteToAcct(price - EP) * Volume; // // Record the peaks // MaxFavourableExcursion = Math.Max(MaxFavourableExcursion, sign * (price - EP)); // MaxAdverseExcursion = Math.Max(MaxAdverseExcursion, sign * (EP - price)); // } // ExitIndex = candle.Index; // } //} /// <summary>Simulate the behaviour of this trade by adding a stream of price ticks</summary> public void Simulate(PriceTick price) { var sign = TradeType.Sign(); // Adding a price tick 'open's an unknown trade if (Result == EResult.Unknown) { Result = EResult.Open; } // If the trade is pending, look for an entry trigger if ((Result == EResult.LimitOrder && Math.Sign(EP - price.Price(sign)) == sign) || (Result == EResult.StopEntryOrder && Math.Sign(price.Price(sign) - EP) == sign)) { Result = EResult.Open; EntryIndex = price.Index; } // Trade has closed out if (Result == EResult.HitSL || Result == EResult.HitTP) { return; } // Otherwise, if this is an open trade. if (Result == EResult.Open) { // SL hit if (SL != null && sign * (price.Price(-sign) - SL.Value) < 0) { NetProfit = sign * Instrument.Symbol.QuoteToAcct(SL.Value - EP) * Volume; MaxAdverseExcursion = sign * (EP - SL.Value); Result = EResult.HitSL; Expiration = price.TimestampUTC.DateTime; } // TP hit else if (TP != null && sign * (price.Price(-sign) - TP.Value) > 0) { NetProfit = sign * Instrument.Symbol.QuoteToAcct(TP.Value - EP) * Volume; MaxFavourableExcursion = sign * (TP.Value - EP); Result = EResult.HitTP; Expiration = price.TimestampUTC.DateTime; } // Update the current profit else { NetProfit = sign * Instrument.Symbol.QuoteToAcct(price.Price(-sign) - EP) * Volume; // Record the peaks MaxFavourableExcursion = Math.Max(MaxFavourableExcursion, sign * (price.Price(-sign) - EP)); MaxAdverseExcursion = Math.Max(MaxAdverseExcursion, sign * (EP - price.Price(-sign))); } ExitIndex = price.Index; } }
/// <summary>Return the normalised value ([-1,+1]) of this order at 'price'. Only valid if the order has SL and TP levels</summary> public double ValueFrac(PriceTick price) { if (SL == null || TP == null) { return(0.0); } var sign = TradeType.Sign(); var win = Maths.Frac(EP, price.Price(+sign), TP.Value); var los = Maths.Frac(EP, price.Price(-sign), SL.Value); if (win < 0) { return(-los); } if (los < 0) { return(+win); } return(win > los ? win : -los); }
/// <summary>Incorporate 'price' into this candle</summary> public void Update(PriceTick price) { High = Math.Max(High, price.Bid); Low = Math.Min(Low, price.Bid); Close = price.Bid; }
/// <summary>Return the normalised value of a position/trade</summary> public static QuoteCurrency ValueFrac(this ITrade pos, PriceTick price) { return(new Order(pos, true).ValueFrac(price)); }
/// <summary>Return the normalised value of a position/trade</summary> public static QuoteCurrency ValueFrac(this PendingOrder pos, PriceTick price) { return(new Order(pos).ValueFrac(price)); }
/// <summary>Return the value of this position if it was to be closed at the given price tick</summary> public static QuoteCurrency ValueAt(this ITrade pos, PriceTick price, bool consider_sl = true, bool consider_tp = true) { return(new Order(pos, true).ValueAt(price, consider_sl, consider_tp)); }