public void TotalPnlLongIsTheSumOfRealizedAndUnrealizedPnlForShortPositions() { var trade = new Trade(); var date = new DateTime(2000, 1, 1); trade.Orders = new List<Order> { new Order { Instrument = _inst, Quantity = -10, FXRateToBase = 1, Price = 100, BuySell = "BUY", TradeDate = date }, new Order { Instrument = _inst, Quantity = 5, FXRateToBase = 1, Price = 95, BuySell = "SELL", TradeDate = date } }; var tracker = new TradeTracker(trade, 1); foreach (Order o in trade.Orders) { tracker.AddOrder(o); } var data = new Dictionary<int, TimeSeries> { { 1, TimeSeriesGenerator.GenerateData(date, date, 90) } }; foreach (TimeSeries ts in data.Values) { ts.ProgressTo(date); } tracker.Update(date, data, null); Assert.AreEqual(5 * 5 + 10 * 5, tracker.TotalPnL); Assert.AreEqual(5 * 5 + 10 * 5, tracker.TotalPnlShort); }
public TradeTracker(Trade trade, decimal optionsCapitalUsageMultiplier) { _optionsCapitalUsageMultiplier = optionsCapitalUsageMultiplier; Positions = new Dictionary<int, Position>() { //dummy position used for cash transactions without a related instrument { NullInstrumentId, new Position(new Instrument(), _optionsCapitalUsageMultiplier)} }; CurrencyPositions = new Dictionary<int, CurrencyPosition>(); CumulativeReturns = new SortedList<DateTime, double>(); CumulativePnL = new SortedList<DateTime, decimal>(); Capital = new AllocatedCapital(); _ordersRemaining = trade.Orders == null ? 0 : trade.Orders.Count; _cashTransactionsRemaining = trade.CashTransactions == null ? 0 : trade.CashTransactions.Count; Trade = trade; _currentEquity = 1; _totalPnL = 0; TodaysPnL = 0; }
public void SetUp() { _inst = new Instrument {ID = 1, Multiplier = 1, AssetCategory = AssetClass.Stock}; _t = new Trade { Orders = new List<Order>(), CashTransactions = new List<CashTransaction>(), FXTransactions = new List<FXTransaction>() }; _dsMock = new Mock<IDataSourcer>(); _dsMock.Setup(x => x.GetData(It.IsAny<Instrument>(), It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<QDMS.BarSize>())) .Returns<Instrument, DateTime, DateTime, QDMS.BarSize>((a, b, c, d) => GenerateData(b, c)); _contextMock = new Mock<IDBContext>(); _dbSetStub = new DbSetStub<EquitySummary>(); var equitySummaries = new List<EquitySummary> { new EquitySummary { Date = new DateTime(2000,1,1), Total = 10000 } }; _dbSetStub.AddRange(equitySummaries); _contextMock.SetupGet(x => x.EquitySummaries).Returns(_dbSetStub); _repository = new TradesRepository(_contextMock.Object, _dsMock.Object, 0.1m); }
/// <summary> /// Create a new trade with a given name. /// Returns the created trade. /// </summary> protected Trade CreateTrade(string name) { var trade = new Trade() { Name = name, Open = true }; TradesRepository.Add(trade); OpenTrades.Add(trade); Logger.Log(LogLevel.Info, "User script {0} created trade {1}", this.GetType().Name, trade); return trade; }
/// <summary> /// Add a tag to a trade. /// </summary> protected void SetTag(Trade trade, string tagName) { var tag = Tags.FirstOrDefault(x => x.Name == tagName); if(tag == null) { Logger.Log(LogLevel.Info, "User script {0} tried to add tag {1} to trade {2}, but it was not found", this.GetType().Name, tagName, trade); return; } SetTag(trade, tag); }
/// <summary> /// Set a trade's strategy. /// </summary> protected void SetStrategy(Trade trade, string strategyName) { var strategy = Strategies.FirstOrDefault(x => x.Name == strategyName); if (strategy == null) { Logger.Log(LogLevel.Warn, "User script {0} tried to set strategy of trade {1} to {2}, but it was not found.", this.GetType().Name, trade, strategyName); return; } SetStrategy(trade, strategy); }
/// <summary> /// Add a tag to a trade. /// </summary> protected void SetTag(Trade trade, Tag tag) { if (tag == null) return; if (trade.Tags != null && trade.Tags.Contains(tag)) return; if(trade.Tags == null) { trade.Tags = new ObservableCollection<Tag>(); } trade.Tags.Add(tag); Logger.Log(LogLevel.Info, "User script {0} added tag {1} to trade {2}", this.GetType().Name, tag, trade); }
public TradeWindow(Trade trade, IDBContext context, IDataSourcer dataSourcer) { Trade = trade; _context = context; InitializeComponent(); ViewModel = new TradeViewModel(trade, dataSourcer, context); DataContext = ViewModel; InitializeFontSizes(); FontFamilyComboBox.ItemsSource = Fonts.SystemFontFamilies; FontSizeComboBox.ItemsSource = FontSizes; //load the notes LoadNotes(); }
public TradeViewModel(Trade trade, IDataSourcer dataSourcer, IDBContext context) : base(null) { context.Trades .Where(x => x.ID == trade.ID) .Include(x => x.Strategy) .Include(x => x.Orders) .Include("Orders.Instrument") .Include("Orders.Currency") .Include(x => x.CashTransactions) .Include("CashTransactions.Instrument") .Include("CashTransactions.Currency") .Include(x => x.FXTransactions) .Include("FXTransactions.FunctionalCurrency") .Include("FXTransactions.FXCurrency") .Load(); Trade = trade; Tracker = TradeSim.SimulateTrade(trade, context, dataSourcer, Properties.Settings.Default.optionsCapitalUsageMultiplier); }
/// <summary> /// Add an order to a trade. /// Returns true if the trade is found and the order successfully added. /// </summary> protected bool SetTrade(Order order, Trade trade) { if(trade == null) { Logger.Log(LogLevel.Warn, "User script {0} tried to add order {1} to a null trade", this.GetType().Name, order); return false; } if(!trade.Open) { Logger.Log(LogLevel.Warn, "User script {0} tried to add order {1} to a closed trade: {2}", this.GetType().Name, order, trade); return false; } TradesRepository.AddOrder(trade, order); Logger.Log(LogLevel.Info, "User script {0} added order {1} to trade {2}", this.GetType().Name, order, trade); return true; }
public static TradeTracker SimulateTrade(Trade trade, IDBContext context, IDataSourcer dataSourcer, decimal optionsCapitalUsageMultiplier) { var tracker = new TradeTracker(trade, optionsCapitalUsageMultiplier); //starting and ending dates DateTime startDate = trade.DateOpened; DateTime endDate; if(!trade.Open && trade.DateClosed != null) { endDate = trade.DateClosed.Value.Date; } else { var lastSummary = context.EquitySummaries.OrderByDescending(x => x.Date).First(); endDate = lastSummary.Date.Date; } var orders = trade.Orders == null ? new List<Order>() : trade.Orders.OrderBy(x => x.TradeDate).ToList(); var cashTransactions = trade.CashTransactions == null ? new List<CashTransaction>() : trade.CashTransactions.OrderBy(x => x.TransactionDate).ToList(); var fxTransactions = trade.FXTransactions == null ? new List<FXTransaction>() : trade.FXTransactions.OrderBy(x => x.DateTime).ToList(); //Grab the data Dictionary<int, TimeSeries> data = GetInstrumentData(trade, dataSourcer, startDate, endDate); Dictionary<int, TimeSeries> fxData = GetFXData(trade, context); DateTime currentDate = startDate.Date; //Loop through the dates while (currentDate <= endDate) { //Progress time series to current date foreach (TimeSeries ts in data.Values) { ts.ProgressTo(currentDate); } foreach (TimeSeries ts in fxData.Values) { ts.ProgressTo(currentDate); } //Add orders while (orders.Count > 0 && orders[0].TradeDate.Date <= currentDate) { tracker.AddOrder(orders[0]); orders.RemoveAt(0); } //Add cash transactions while (cashTransactions.Count > 0 && cashTransactions[0].TransactionDate.Date <= currentDate) { tracker.AddCashTransaction(cashTransactions[0]); cashTransactions.RemoveAt(0); } //add fx transactions while (fxTransactions.Count > 0 && fxTransactions[0].DateTime.Date <= currentDate) { tracker.AddFXTransaction(fxTransactions[0]); fxTransactions.RemoveAt(0); } tracker.Update(currentDate, data, fxData); if (orders.Count == 0 && cashTransactions.Count == 0 && fxTransactions.Count == 0 && !tracker.Open) break; currentDate = currentDate.AddDays(1); } return tracker; }
public TradeViewModel() : base(null) { Trade = new Trade(); }
/// <summary> /// Close a trade. /// </summary> protected void CloseTrade(Trade trade) { if(!trade.Open) { Logger.Log(LogLevel.Info, "User script {0} tried to close trade {1} but it was already closed", this.GetType().Name, trade); return; } if(!trade.IsClosable()) { Logger.Log(LogLevel.Info, "User script {0} tried to close trade {1} but the trade can not be closed", this.GetType().Name, trade); return; } trade.Open = false; TradesRepository.UpdateStats(trade); Logger.Log(LogLevel.Info, "User script {0} closed trade {1}", this.GetType().Name, trade); }
/// <summary> /// Set a trade's strategy. /// </summary> protected void SetStrategy(Trade trade, Strategy strategy) { trade.Strategy = strategy; Logger.Log(LogLevel.Info, "User script {0} set strategy of trade {1} to {2}", this.GetType().Name, trade, strategy); }
private void TradePickerNewTradeTextBox_KeyDown(object sender, KeyEventArgs e) { if(e.Key == Key.Enter && !String.IsNullOrEmpty(TradePickerNewTradeTextBox.Text)) { var selectedOrder = (Order)OrdersGrid.SelectedItem; var newTrade = new Trade { Name = TradePickerNewTradeTextBox.Text, Open = true }; Context.Trades.Add(newTrade); newTrade.Tags = new List<Tag>(); Task.Run(() => { TradesRepository.AddOrder(newTrade, selectedOrder); TradesRepository.Save(); }); TradePickerNewTradeTextBox.Text = ""; OrdersGridTradePickerPopup.IsOpen = false; OrdersGrid.CommitEdit(); } }
public void AddingOrderInForeignCurrencyResultsInFxPositionAddition() { var trade = new Trade(); var date = new DateTime(2000, 1, 1); var eur = new Currency { ID = 2, Name = "EUR" }; trade.Orders = new List<Order> { new Order { Instrument = _inst, Quantity = 10, FXRateToBase = 1.5m, Multiplier = 1, Price = 100, BuySell = "BUY", TradeDate = date, Currency = eur, CurrencyID = 2 }, }; var tracker = new TradeTracker(trade, 1); foreach (Order o in trade.Orders) { tracker.AddOrder(o); } Assert.IsTrue(tracker.CurrencyPositions.ContainsKey(2)); Assert.IsTrue(tracker.CurrencyPositions[2].Quantity == -10 * 100); Assert.IsTrue(tracker.CurrencyPositions[2].CostBasis == 1.5m); }
private static List<int> GetNeededFXIDs(Trade trade) { var currencyIDs = new List<int>(); if (trade.Orders != null) { currencyIDs.AddRange(trade.Orders.Select(x => x.CurrencyID)); } if (trade.CashTransactions != null) { currencyIDs.AddRange(trade.CashTransactions.Select(x => x.CurrencyID)); } if (trade.FXTransactions != null) { currencyIDs.AddRange(trade.FXTransactions.Select(x => x.FXCurrencyID)); } return currencyIDs.Distinct().ToList(); }
private static Dictionary<int, TimeSeries> GetFXData(Trade trade, IDBContext context) { List<int> neededFXIDs = GetNeededFXIDs(trade); var fxData = new Dictionary<int, TimeSeries>(); foreach (int id in neededFXIDs) { if (id <= 1) continue; int id1 = id; fxData.Add(id, TimeSeriesFromFXRates(context.FXRates.Where(x => x.FromCurrencyID == id1).OrderBy(x => x.Date))); } return fxData; }
public void SetTradeStats(Trade trade) { var positions = Positions.Values; //Capital usage stats trade.CapitalTotal = Capital.Gross.Count(x => x > 0) > 0 ? Capital.Gross.Where(x => x > 0).Average() : 0; trade.CapitalLong = Capital.Long.Count(x => x > 0) > 0 ? Capital.Long.Where(x => x > 0).Average() : 0; trade.CapitalShort = Capital.Short.Count(x => x > 0) > 0 ? Capital.Short.Where(x => x > 0).Average() : 0; trade.CapitalNet = trade.CapitalLong - trade.CapitalShort; //Realized dollar result stats trade.ResultDollars = RealizedPnL; trade.ResultDollarsLong = RealizedPnLLong; trade.ResultDollarsShort = RealizedPnLShort; //Realized percent result stats trade.ResultPct = trade.CapitalTotal > 0 ? (double)(trade.ResultDollars / trade.CapitalTotal) : 0; trade.ResultPctLong = trade.CapitalLong > 0 ? (double)(trade.ResultDollarsLong / trade.CapitalLong) : 0; trade.ResultPctShort = trade.CapitalShort > 0 ? (double)(trade.ResultDollarsShort / trade.CapitalShort) : 0; //Commissions if (trade.Orders != null) { trade.Commissions = trade.Orders.Sum(x => x.CommissionInBase); } //Unrealized result stats trade.UnrealizedResultDollars = TotalPnL - RealizedPnL; trade.UnrealizedResultDollarsLong = positions.Sum(x => x.PnLLong - x.RealizedPnLLong); trade.UnrealizedResultDollarsShort = positions.Sum(x => x.PnLShort - x.RealizedPnLShort); //Unrealized percent result stats trade.UnrealizedResultPct = trade.CapitalTotal > 0 ? (double)(trade.UnrealizedResultDollars / trade.CapitalTotal) : 0; trade.UnrealizedResultPctLong = trade.CapitalLong > 0 ? (double)(trade.UnrealizedResultDollarsLong / trade.CapitalLong) : 0; trade.UnrealizedResultPctShort = trade.CapitalShort > 0 ? (double)(trade.UnrealizedResultDollarsShort / trade.CapitalShort) : 0; }
public void AddingCashTransactionInForeignCurrencyResultsInFxPositionAddition() { var trade = new Trade(); var date = new DateTime(2000, 1, 1); var eur = new Currency { ID = 2, Name = "EUR" }; var ct = new CashTransaction { InstrumentID = 1, Currency = eur, CurrencyID = 2, Amount = 50, FXRateToBase = 1.5m, Instrument = _inst, TransactionDate = date, AssetCategory = AssetClass.Stock }; trade.CashTransactions = new List<CashTransaction> { ct }; var tracker = new TradeTracker(trade, 1); foreach (CashTransaction c in trade.CashTransactions) { tracker.AddCashTransaction(c); } Assert.IsTrue(tracker.CurrencyPositions.ContainsKey(2)); Assert.IsTrue(tracker.CurrencyPositions[2].Quantity == 50); Assert.IsTrue(tracker.CurrencyPositions[2].CostBasis == 1.5m); }
private static Dictionary<int, TimeSeries> GetInstrumentData(Trade trade, IDataSourcer dataSourcer, DateTime startDate, DateTime endDate) { var data = new Dictionary<int, TimeSeries>(); if (trade.Orders == null) return data; foreach (EntityModel.Instrument inst in trade.Orders.Select(x => x.Instrument).Distinct(x => x.ID)) { data.Add(inst.ID, new TimeSeries(dataSourcer.GetData(inst, startDate, endDate))); } return data; }
public void TodaysPnlResetsEvenWhenTrackerIsNotOpen() { var trade = new Trade(); var date = new DateTime(2000, 1, 1); trade.Orders = new List<Order> { new Order { Instrument = _inst, Quantity = -10, FXRateToBase = 1, Price = 100, BuySell = "BUY", TradeDate = date }, new Order { Instrument = _inst, Quantity = 5, FXRateToBase = 1, Price = 95, BuySell = "SELL", TradeDate = date } }; var tracker = new TradeTracker(trade, 1); foreach (Order o in trade.Orders) { tracker.AddOrder(o); } var data = new Dictionary<int, TimeSeries> { { 1, TimeSeriesGenerator.GenerateData(date, date.AddDays(1), 90) } }; foreach (TimeSeries ts in data.Values) { ts.ProgressTo(date); } tracker.Update(date, data, null); Assert.AreEqual(5 * 5 + 10 * 5, tracker.TodaysPnL); data[1].ProgressTo(date.AddDays(1)); tracker.Update(date.AddDays(1), data, null); Assert.AreEqual(0, tracker.TodaysPnL); }
public void CapitalUsageCorrectlyTracked() { var inst2 = new Instrument { ID = 2, Multiplier = 1, AssetCategory = AssetClass.Stock }; var order1 = new Order { Instrument = _inst, InstrumentID = _inst.ID, Multiplier = 1, FXRateToBase = 1, Price = 10, Quantity = 100, CurrencyID = 1, BuySell = "BUY", IsReal = true, TradeDate = new DateTime(2000, 1, 2) }; var order2 = new Order { Instrument = inst2, InstrumentID = inst2.ID, Multiplier = 1, FXRateToBase = 1, Price = 20, Quantity = -100, CurrencyID = 1, BuySell = "SELL", IsReal = true, TradeDate = new DateTime(2000, 1, 3, 12, 0, 0) }; var order3 = new Order { Instrument = inst2, InstrumentID = inst2.ID, Multiplier = 1, FXRateToBase = 1, Price = 19, Quantity = 100, CurrencyID = 1, BuySell = "BUY", IsReal = true, TradeDate = new DateTime(2000, 1, 3, 13, 0, 0) }; var trade = new Trade { Orders = new List<Order> { order1, order2, order3 } }; var trades = new List<Trade> { trade }; _data = new Dictionary<int, TimeSeries> { { 1, TimeSeriesGenerator.GenerateData(new DateTime(2000,1,1), new DateTime(2000,2,1), 11) }, { 2, TimeSeriesGenerator.GenerateData(new DateTime(2000,1,1), new DateTime(2000,2,1), 20) } }; var tracker = new PortfolioTracker(_data, _fxData, trades, "test", new DateTime(2000, 1, 1), 1); var date = new DateTime(2000, 1, 1); foreach (TimeSeries ts in _data.Values) { ts.ProgressTo(date); } tracker.ProcessItemsAt(date); tracker.OnDayClose(date, 10000); Assert.AreEqual(0, tracker.Capital.Gross.Last()); date = date.AddDays(1); foreach (TimeSeries ts in _data.Values) { ts.ProgressTo(date); } tracker.ProcessItemsAt(date); tracker.OnDayClose(date, 10000); Assert.AreEqual(10 * 100, tracker.Capital.Gross.Last()); Assert.AreEqual(10 * 100, tracker.Capital.Long.Last()); date = date.AddDays(1); foreach (TimeSeries ts in _data.Values) { ts.ProgressTo(date); } tracker.ProcessItemsAt(date); tracker.OnDayClose(date, 10000); Assert.AreEqual(11 * 100 + 20 * 100, tracker.Capital.Gross.Last()); Assert.AreEqual(11 * 100, tracker.Capital.Long.Last()); Assert.AreEqual(20 * 100, tracker.Capital.Short.Last()); }
public void TotalPnlLongIsTheSumOfRealizedAndUnrealizedPnlForCurrencyPositions() { var trade = new Trade(); var date = new DateTime(2000, 1, 1); var fxCurrency = new Currency { ID = 2, Name = "CAD" }; trade.FXTransactions = new List<FXTransaction> { new FXTransaction { FXCurrency = fxCurrency, Quantity = 1000, Proceeds = 1500, Cost = -1500 }, new FXTransaction { FXCurrency = fxCurrency, Quantity = -500, Proceeds = -850, Cost = 850 }, }; var tracker = new TradeTracker(trade, 1); foreach (FXTransaction fxt in trade.FXTransactions) { tracker.AddFXTransaction(fxt); } var data = new Dictionary<int, TimeSeries> { { 2, TimeSeriesGenerator.GenerateData(date, date, 1.55m) } }; foreach (TimeSeries ts in data.Values) { ts.ProgressTo(date); } tracker.Update(date, new Dictionary<int, TimeSeries>(), data); Assert.AreEqual(100 + 500 * (1.55m - 1.5m), tracker.TotalPnL); }
private void OrdersContextMenuNewTradeTextBox_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { //close the context menu var ordersGridContextMenu = (ContextMenu)Resources["OrdersGridContextMenu"]; var ordersContextMenuNewTradeTextBox = (TextBox)sender; ordersGridContextMenu.IsOpen = false; //only add a trade if there's a name in the box if (String.IsNullOrEmpty(ordersContextMenuNewTradeTextBox.Text)) return; List<Order> selectedOrders = OrdersGrid.SelectedItems.Cast<Order>().ToList(); var newTrade = new Trade { Name = ordersContextMenuNewTradeTextBox.Text, Open = true }; Context.Trades.Add(newTrade); newTrade.Tags = new List<Tag>(); Task.Run(() => { foreach (Order o in selectedOrders) { TradesRepository.AddOrder(newTrade, o); } TradesRepository.Save(); }); ordersContextMenuNewTradeTextBox.Text = ""; } }