protected sealed override void OnTick() { ++TickNumber; Debugging.BreakOnPointOfInterest(); // Emergency stop on large draw-down BalanceMinimum = Math.Max((double)BalanceMinimum, Account.Balance * (1.0 - Settings.MaxDrawDownFrac)); if (Account.Equity < BalanceMinimum) { Debugging.Trace("Account equity (${0}) dropped below the balance minimum (${1}). Stopping".Fmt(Account.Equity, BalanceMinimum)); Print("Account equity (${0}) dropped below the balance minimum (${1}). Stopping".Fmt(Account.Equity, BalanceMinimum)); CloseAllPositions("Emergency Stop"); Stop(); return; } // Raise the Bot.Tick event before stepping the bot // Instruments are signed up to the Tick event so they will be updated first base.OnTick(); Tick.Raise(this); try { // Update the account info Broker.Update(); // Remove position sets that don't have any active positions var set_ids = Positions.Select(x => Guid_.Parse(x.Comment)).NotNull().ToHashSet(x => x.Value); foreach (var set_id in PositionSets.Keys.ToArray()) { if (set_ids.Contains(set_id)) { continue; } PositionSets.Remove(set_id); } // Step active position managers foreach (var pm in PositionManagers) { pm.Step(); } // Entry cool down if (EntryCooldown != 0 && Instrument.NewCandle) { --EntryCooldown; } // Step the bot Step(); } catch (Exception ex) { Debugging.Trace(ex.Message); Debugging.Trace(ex.StackTrace); } }
protected override void OnPositionOpened(Position position) { // Prevent positions being entered on the same bulge EntryCooldown = NonIntersectingCount; { // Adjust the stop loss to allow for slip var mcs = Instrument.MCS; var sign = position.Sign(); var ep = position.EntryPrice; var sl = ep - sign * mcs * SLFrac; Broker.ModifyOrder(Instrument, position, sl: sl); } // If the main position of a position set opens, create a pending order in the opposite direction. // This is designed to catch the case when we choose a break-out trade but it's actually a reversal, or visa-versa. var id = Guid_.Parse(position.Comment); if (id != null && PositionSets[id.Value].Count == 1) { var mcs = Instrument.MCS; var sign = -position.Sign(); var tt = CAlgo.SignToTradeType(sign); var rel = Math.Abs(position.EntryPrice - position.StopLoss.Value) * 0.75; var ep = MA0[0] + sign * rel; var sl = ep - sign * mcs * SLFrac; var tp = (QuoteCurrency?)null; var vol = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk: Risk); var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol, comment: Guid.NewGuid().ToString()) { Expiration = Instrument.ExpirationTime(2) }; Broker.CreatePendingOrder(trade); } // Close positions if there is a breakout in the wrong direction PositionManagers.Add(new PositionManagerBreakOut(this, position, CloseBreakoutPeriods, only_if_in_profit: true)); // Close positions when they fail to make new peaks PositionManagers.Add(new PositionManagerTopDrop(this, position, CloseTopDropCount, only_if_in_profit: true)); // Close positions when there's a steady stream of adverse candles PositionManagers.Add(new PositionManagerAdverseCandles(this, position, CloseAdverseCount)); }
private void HandlePositionOpened(PositionOpenedEventArgs args) { // Only watch positions created by this bot var position = args.Position; if (position.Label != Label) { return; } try { // Add the position to the set it belongs to, or begin a new set var id = Guid_.Parse(position.Comment); if (id != null) { if (PositionSets.ContainsKey(id.Value)) { PositionSets[id.Value].Add(position.Id); } else { PositionSets[id.Value] = new List <int>(new[] { position.Id }); } } // Notify position closed if (PositionOpened != null) { PositionOpened(this, args); } OnPositionOpened(position); } catch (Exception ex) { Debugging.Trace(ex.Message); Debugging.Trace(ex.StackTrace); } }
private void HandlePositionClosed(PositionClosedEventArgs args) { // Only watch positions created by this strategy var position = args.Position; if (position.Label != Label) { return; } // Close all positions in the same set var id = Guid_.Parse(position.Comment); if (id != null && PositionSets.ContainsKey(id.Value)) { var set = PositionSets[id.Value]; Broker.ClosePositions(Positions.Where(x => set.Contains(x.Id)), "Closing Set"); PositionSets.Remove(id.Value); } // Remove any position managers that are managing 'position' PositionManagers.RemoveIf(x => x.Position.Id == position.Id); try { // Notify position closed if (PositionClosed != null) { PositionClosed(this, args); } OnPositionClosed(position); } catch (Exception ex) { Debugging.Trace(ex.Message); Debugging.Trace(ex.StackTrace); } }