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