using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Web.UI.WebControls; using TradeIdeas.MiscSupport; using TradeIdeas.TIProGUI; namespace TIProAutoTradeExtension { public class ProfitSaveExit: IAdvancedExit { private Position _position = null; public Position Position { get { return _position; } set { _position = value; } } private bool _triggered = false; public bool Triggered { get { return _triggered; } } public ProfitSaveExit(Position position) { _position = position; } /// /// Smart Stop value retrieved from RowData from original alert signal. /// private decimal _smartStop = 0; /// /// The first stop move trigger level. When the price hits this level, the stop should be moved to _moveStopLevel /// private decimal _moveStopTriggerLevel = 0; /// /// The level to which the stop price should be moved when the price reaches _moveStopTriggerLevel. /// private decimal _moveStopLevel = 0; /// /// The second stop move trigger level. When the price hits this level, the stop should be moved to _moveStopLevelSecond /// private decimal _moveStopTriggerLevelSecond = 0; /// /// The level to which the stop price should be moved when the price reaches _moveStopTriggerLevelSecond. /// private decimal _moveStopLevelSecond = 0; /// /// The first stop move trigger level. When the price hits this level, the stop should be moved to _moveStopLevelThird /// private decimal _moveStopTriggerLevelThird = 0; /// /// The level to which the stop price should be moved when the price reaches _moveStopTriggerLevelThird. /// private decimal _moveStopLevelThird = 0; /// /// Used to keep track of the current stop level (0, 1, 2, 3) /// private int _currentMoveStopMode = 0; private decimal _currentStopPrice = 0; public void Evaluate() { if (null != _position && !_triggered) { if (null != _position.Instrument) { decimal entryPrice = _position.AverageCost; if (_position.Instrument.SmartStop.HasValue) _smartStop = (decimal)_position.Instrument.SmartStop.Value; if (null != _position.StopLossOrder) { foreach (TradeOrder stopLossOrder in _position.StopLossOrder.ToList()) { decimal? stopLossPrice = stopLossOrder.StopPrice; if (_smartStop > 0 && stopLossPrice.HasValue) { bool isLong = _position.Shares > 0; _currentStopPrice = _position.StopLossPrice.Value; if (null != stopLossOrder && stopLossOrder.FilledShares != 0) { _triggered = true; return; } if (entryPrice > 10) { _moveStopTriggerLevel = entryPrice + _smartStop / 2; _moveStopLevel = entryPrice + _smartStop / 3; _moveStopTriggerLevelSecond = entryPrice + _smartStop; _moveStopLevelSecond = entryPrice + _smartStop / 2; _moveStopTriggerLevelThird = entryPrice + _smartStop * 2; _moveStopLevelThird = entryPrice + _smartStop; if (!isLong) { _moveStopTriggerLevel = entryPrice - _smartStop / 2; _moveStopLevel = entryPrice - _smartStop / 3; _moveStopTriggerLevelSecond = entryPrice - _smartStop; _moveStopLevelSecond = entryPrice - _smartStop / 2; _moveStopTriggerLevelThird = entryPrice - _smartStop * 2; _moveStopLevelThird = entryPrice - _smartStop; } } else { _moveStopTriggerLevel = entryPrice + (_smartStop - (decimal)0.05); _moveStopLevel = entryPrice + _smartStop / 3; _moveStopTriggerLevelSecond = entryPrice + _smartStop * 2; _moveStopLevelSecond = entryPrice + _smartStop; if (!isLong) { _moveStopTriggerLevel = entryPrice - (_smartStop - (decimal)0.05); _moveStopLevel = entryPrice - _smartStop / 3; _moveStopTriggerLevelSecond = entryPrice - _smartStop * 2; _moveStopLevelSecond = entryPrice - _smartStop; } } LogMessage("[ProfitSaveExit] " + ToDebugString()); if (isLong && _position.Last > _moveStopTriggerLevel && _currentMoveStopMode == 0 && _moveStopTriggerLevel > 0) { _currentMoveStopMode = 1; _currentStopPrice = _moveStopLevel; LogMessage("[ProfitSaveExit] Changed from 0 to 1: " + ToDebugString()); } else if (isLong && _position.Last > _moveStopTriggerLevelSecond && _currentMoveStopMode < 2 && _moveStopTriggerLevelSecond > 0) { _currentMoveStopMode = 2; _currentStopPrice = _moveStopLevelSecond; LogMessage("[ProfitSaveExit] Changed to 2: " + ToDebugString()); } else if (isLong && _position.Last > _moveStopTriggerLevelThird && _currentMoveStopMode < 3 && _moveStopTriggerLevelThird > 0) { _currentMoveStopMode = 3; _currentStopPrice = _moveStopLevelThird; LogMessage("[ProfitSaveExit] Changed to 3: " + ToDebugString()); } else if (!isLong && _position.Last < _moveStopTriggerLevel && _currentMoveStopMode == 0 && _moveStopTriggerLevel > 0) { _currentMoveStopMode = 1; _currentStopPrice = _moveStopLevel; LogMessage("[ProfitSaveExit] Changed from 0 to 1: " + ToDebugString()); } else if (!isLong && _position.Last < _moveStopTriggerLevelSecond && _currentMoveStopMode < 2 && _moveStopTriggerLevelSecond > 0) { _currentMoveStopMode = 2; _currentStopPrice = _moveStopLevelSecond; LogMessage("[ProfitSaveExit] Changed to 2: " + ToDebugString()); } else if (!isLong && _position.Last < _moveStopTriggerLevelThird && _currentMoveStopMode < 3 && _moveStopTriggerLevelThird > 0) { _currentMoveStopMode = 3; _currentStopPrice = _moveStopLevelThird; LogMessage("[ProfitSaveExit] Changed to 3: " + ToDebugString()); } double minIncrement = 0.01; if (_position.Instrument.MinMove.HasValue) minIncrement = _position.Instrument.MinMove.Value; decimal preRoundedStopPrice = _currentStopPrice; _currentStopPrice = BrokerManager.RoundToNearest(_currentStopPrice, minIncrement); if (stopLossOrder.IsLive && stopLossOrder.FilledShares == 0 && stopLossOrder.StopPrice != _currentStopPrice) { LogMessage("[ProfitSaveExit] Updating stop price from " + stopLossOrder.StopPrice + " to " + _currentStopPrice + " (pre rounding: " + preRoundedStopPrice + ") for " + ToDebugString()); TradeOrder updatedOrder = new TradeOrder(stopLossOrder); updatedOrder.StopPrice = _currentStopPrice; _position.Broker.ModifyOrder(updatedOrder); } } } } } else { LogMessage("Didn't find SmartStop for position in ProfitSaveExit: " + _position.Symbol + ", " + ToDebugString()); } } } private void LogMessage(string message) { try { string robotDataDirectory = GuiEnvironment.DataDirectory + "\\robotlogs"; if (!Directory.Exists(robotDataDirectory)) Directory.CreateDirectory(robotDataDirectory); string logFile = robotDataDirectory + "\\log." + ServerFormats.Now.ToString("yyyyMMdd") + ".txt"; using (FileStream fileStream = new FileStream(logFile, FileMode.Append, FileAccess.Write, FileShare.None)) { using (StreamWriter streamWriter = new StreamWriter(fileStream)) { try { streamWriter.WriteLine(ServerFormats.Now.ToString("yyyy-MM-dd hh:mm:ss.ffff") + "\tProfitSaveExit\t" + message); } catch { } } } } catch { } } /// /// Used for debugging purposes - gives a string representation of the current status of the Profit Save exit. /// /// private string ToDebugString() { string toReturn = ""; toReturn += "ProfitSaveExit: "; if (null != _position) { toReturn += ", symbol=" + _position.Symbol; toReturn += ", last=" + _position.Instrument.Last; if (_position.Instrument.MinMove.HasValue) toReturn += ", minmove=" + _position.Instrument.MinMove.Value; else toReturn += ", minmove=NULL"; } else toReturn += ", symbol=N/A"; toReturn += ", mode=" + _currentMoveStopMode; toReturn += ", triggered=" + _triggered; toReturn += ", stop=" + _currentStopPrice; toReturn += ", movestoplevel=" + _moveStopLevel; toReturn += ", movestoptriggerlevel=" + _moveStopTriggerLevel; toReturn += ", movestoplevel2=" + _moveStopLevelSecond; toReturn += ", movestoptriggerlevel2=" + _moveStopTriggerLevelSecond; toReturn += ", movestoplevel3=" + _moveStopLevelThird; toReturn += ", movestoptriggerlevel3=" + _moveStopTriggerLevelThird; if (null != _position && null != _position.StopLossOrder) { foreach (TradeOrder order in _position.StopLossOrder.ToList()) { toReturn += ", stoplossid=" + order.OrderId; toReturn += ", stoplosscreated=" + order.Created.ToString("hh:mm:ss"); toReturn += ", stoplossupdated=" + order.Updated.ToString("hh:mm:ss"); } } return toReturn; } } }