Пример #1
0
        ///// <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;
            }
        }
Пример #2
0
        /// <summary>
        /// Create a trade with automatic SL and TP levels set.
        /// SL/TP levels are set based on the current account balance (even if 'idx' != 0)</summary>
        /// <param name="instr">The instrument to be traded</param>
        /// <param name="tt">Whether to buy or sell</param>
        /// <param name="label">Optional. An identifying name for the trade</param>
        /// <param name="ep">Optional. The price at which the trade was entered. (default is current ask/bid price)</param>
        /// <param name="sl">Optional. The stop loss (absolute) to use instead of automatically finding one</param>
        /// <param name="tp">Optional. The take profit (absolute) to use instead of automatically finding one</param>
        /// <param name="risk">Optional. Scaling factor for the amount to risk. (default is 1.0)</param>
        /// <param name="comment">Optional. A comment/tag associated with the trade</param>
        /// <param name="idx">Optional. The instrument index of when the trade was created. (default is the current time)</param>
        public Trade(Instrument instr, TradeType tt, string label = null, QuoteCurrency?ep = null, QuoteCurrency?sl = null, QuoteCurrency?tp = null, double?risk = null, string comment = null, Idx?idx = null, EResult result = EResult.Unknown)
            : this(instr, tt, label, 0, null, null, 0, comment : comment, idx : idx, result : result)
        {
            try
            {
                var bot   = instr.Bot;
                var sign  = tt.Sign();
                Idx index = idx ?? 0;
                bot.Debugging.Trace("Creating Trade (Index = {0})".Fmt(TradeIndex));

                // If the index == 0, add the fractional index amount
                if (index == 0)
                {
                    var ticks_elapsed    = bot.UtcNow.Ticks - instr.Latest.Timestamp;
                    var ticks_per_candle = instr.TimeFrame.ToTicks();
                    EntryIndex += Maths.Clamp((double)ticks_elapsed / ticks_per_candle, 0.0, 1.0);
                    ExitIndex   = EntryIndex;
                }

                // Set the trade entry price
                EP = ep ?? (index == 0
                                        ? (QuoteCurrency)instr.CurrentPrice(sign)                                   // Use the latest price
                                        : (QuoteCurrency)instr[index].Open + (sign > 0 ? instr.Symbol.Spread : 0)); // Use the open price of the candle at 'index'

                // Choose a risk scaler
                risk = risk ?? 1.0;

                // Find the account currency value of the available risk
                var balance_to_risk = bot.Broker.BalanceToRisk * risk.Value;
                if (balance_to_risk == 0)
                {
                    throw new Exception("Insufficient available risk. Current Risk: {0}%, Maximum Risk: {1}%".Fmt(100 * bot.Broker.TotalRiskFrac, 100.0 * bot.Settings.MaxRiskFrac));
                }

                // Require the SL to be at least 2 * the median candle size
                var volatility = instr.Symbol.QuoteToAcct(2 * instr.MCS * instr.Symbol.VolumeMin);
                if (balance_to_risk < volatility)
                {
                    throw new Exception("Insufficient available risk. Volatility: {0}, Balance To Risk: {1}".Fmt(volatility, balance_to_risk));
                }

                // Get the instrument to recommend trade exit conditions
                var exit = instr.ChooseTradeExit(tt, EP, idx: index, risk: risk);
                TP     = tp != null ? tp.Value : exit.TP;
                SL     = sl != null ? sl.Value : exit.SL;
                Volume = sl != null?instr.Bot.Broker.ChooseVolume(instr, sl.Value / risk.Value) : exit.Volume;
            }
            catch (Exception ex)
            {
                Error = ex;
            }
        }
Пример #3
0
        /// <summary>Return the value (in quote currency) of this order when the price is at 'price' (not scaled by volume)
        /// Positive values mean in profit. Negative values mean loss</summary>
        public QuoteCurrency ValueAt(QuoteCurrency price, bool consider_sl, bool consider_tp)
        {
            var sign = TradeType.Sign();

            // If 'price' is beyond the stop loss, clamp at the stop loss value
            if (consider_sl && SL != null && Maths.Sign(SL.Value - price) == sign)
            {
                price = SL.Value;
            }

            // If 'price' is beyond the take profit, clamp at the take profit value
            if (consider_tp && TP != null && Maths.Sign(price - TP.Value) == sign)
            {
                price = TP.Value;
            }

            // Return the position value in quote currency
            return(sign * (price - EP));
        }
Пример #4
0
        /// <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);
        }