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