/// <summary> /// Run for each day that the Tax Lot remains open / partially closed /// </summary> /// <param name="env"></param> /// <param name="element">Trade we aee interested in</param> public void DailyEvent(PostingEngineEnvironment env, Transaction element) { double fxrate = 1.0; // Lets get fx rate if needed if (!element.SettleCurrency.Equals(env.BaseCurrency)) { fxrate = Convert.ToDouble(FxRates.Find(env.ValueDate, element.SettleCurrency).Rate); } // Calculate the unrealized PNL if (env.TaxLotStatus.ContainsKey(element.LpOrderId)) { // Determine if we need to accumulate unrealized PNL var taxlot = env.TaxLotStatus[element.LpOrderId]; // Check to see if the TaxLot is still open and it has a non zero Quantity if (!taxlot.Status.ToLowerInvariant().Equals("closed") && Math.Abs(taxlot.Quantity) > 0) { var listOfTags = new List <Tag> { Tag.Find("SecurityType"), Tag.Find("CustodianCode") }; // We have an open / partially closed tax lot so now need to calculate unrealized Pnl var quantity = taxlot.Quantity; var prevEodPrice = 0.0; var eodPrice = 0.0; if (env.ValueDate == element.TradeDate) { eodPrice = MarketPrices.GetPrice(env, env.ValueDate, element).Price; prevEodPrice = element.SettleNetPrice; } else { prevEodPrice = MarketPrices.GetPrice(env, env.PreviousValueDate, element).Price; eodPrice = MarketPrices.GetPrice(env, env.ValueDate, element).Price; } var unrealizedPnl = CommonRules.CalculateUnrealizedPnl(env, taxlot); AccountToFrom fromToAccounts = null; if (element.IsDerivative()) { var originalAccount = AccountUtils.GetDerivativeAccountType(unrealizedPnl); if (originalAccount.Contains("(Liabilities)")) { // This needs to be registered as a Credit to the Libabilities unrealizedPnl *= -1; } fromToAccounts = new AccountUtils().GetAccounts(env, originalAccount, "Change in Unrealized Derivatives Contracts at Fair Value", listOfTags, taxlot.Trade); } else { var originalAccount = taxlot.Side == "SHORT" ? "Mark to Market Shorts" : "Mark to Market Longs"; fromToAccounts = new AccountUtils().GetAccounts(env, originalAccount, "CHANGE IN UNREALIZED GAIN/(LOSS)", listOfTags, taxlot.Trade); } var fund = env.GetFund(element); var debit = new Journal(element) { Account = fromToAccounts.From, When = env.ValueDate, Symbol = taxlot.Symbol, Quantity = quantity, FxRate = fxrate, Value = env.SignedValue(fromToAccounts.From, fromToAccounts.To, true, unrealizedPnl), CreditDebit = env.DebitOrCredit(fromToAccounts.From, unrealizedPnl), StartPrice = prevEodPrice, EndPrice = eodPrice, Event = Event.DAILY_UNREALIZED_PNL, Fund = fund, }; var credit = new Journal(element) { Account = fromToAccounts.To, When = env.ValueDate, FxRate = fxrate, Quantity = quantity, Value = env.SignedValue(fromToAccounts.From, fromToAccounts.To, false, unrealizedPnl), CreditDebit = env.DebitOrCredit(fromToAccounts.To, env.SignedValue(fromToAccounts.From, fromToAccounts.To, false, unrealizedPnl)), Event = Event.DAILY_UNREALIZED_PNL, StartPrice = prevEodPrice, EndPrice = eodPrice, Fund = fund, }; Logger.Info($"[Journals] ==> From : {debit.CreditDebit}::{debit.Value}::{debit.Account.Type.Category.Name} --> To : {credit.CreditDebit}::{credit.Value}::{credit.Account.Type.Category.Name} ({unrealizedPnl})"); env.Journals.AddRange(new[] { debit, credit }); // For Derivatives this is un-necessary as we do not have an investment at cost, but we do have Fx on unsettled if (taxlot.Quantity != 0.0) { if (element.TradeDate != env.ValueDate) { new FxPosting().CreateFxUnsettled(env, element); } } } } else { if (fxrate != 1.0) { if (element.TradeDate != env.ValueDate && element.SettleDate >= env.ValueDate) { /* * var fxJournals = FxPosting.CreateFx( * env, * "DUE FROM/(TO) PRIME BROKERS ( Unsettled Activity )", * "fx gain or loss on unsettled balance", * "daily", * element.Quantity, null, element); * env.Journals.AddRange(fxJournals); */ } } } }
private void GenerateDailyUnrealized(PostingEngineEnvironment env, TaxLotStatus taxLotStatus, Transaction element, double quantity, double fxRate) { var prevEodPrice = 0.0; var eodPrice = 0.0; if (env.ValueDate == taxLotStatus.Trade.TradeDate) { prevEodPrice = taxLotStatus.Trade.SettleNetPrice; eodPrice = MarketPrices.GetPrice(env, env.ValueDate, taxLotStatus.Trade).Price; } else { prevEodPrice = MarketPrices.GetPrice(env, env.PreviousValueDate, taxLotStatus.Trade).Price; eodPrice = MarketPrices.GetPrice(env, env.ValueDate, taxLotStatus.Trade).Price; } var endPrice = element.SettleNetPrice; if (taxLotStatus.Quantity == 0.0) { eodPrice = endPrice; } var unrealizedPnl = CommonRules.CalculateUnrealizedPnl(env, taxLotStatus, quantity, eodPrice); var originalAccount = taxLotStatus.Side == "SHORT" ? "Mark to Market Shorts" : "Mark to Market Longs"; var fromToAccounts = new AccountUtils().GetAccounts(env, originalAccount, "CHANGE IN UNREALIZED GAIN/(LOSS)", listOfTags, taxLotStatus.Trade); if (taxLotStatus.Side == "SHORT") { unrealizedPnl *= -1; } var fund = env.GetFund(taxLotStatus.Trade); var debit = new Journal(taxLotStatus.Trade) { Account = fromToAccounts.From, When = env.ValueDate, Symbol = taxLotStatus.Symbol, Quantity = quantity, FxRate = fxRate, Value = env.SignedValue(fromToAccounts.From, fromToAccounts.To, true, unrealizedPnl), CreditDebit = env.DebitOrCredit(fromToAccounts.From, unrealizedPnl), StartPrice = prevEodPrice, EndPrice = eodPrice, Event = Event.DAILY_UNREALIZED_PNL, Fund = fund, }; var credit = new Journal(debit) { Account = fromToAccounts.To, Value = env.SignedValue(fromToAccounts.From, fromToAccounts.To, false, unrealizedPnl), CreditDebit = env.DebitOrCredit(fromToAccounts.To, unrealizedPnl), }; env.Journals.AddRange(new[] { debit, credit }); if (fxRate != 1.0) { if (element.TradeDate != env.ValueDate && element.SettleDate >= env.ValueDate) { var fxJournals = FxPosting.CreateFx( env, "DUE FROM/(TO) PRIME BROKERS ( Unsettled Activity )", "fx gain or loss on unsettled balance", "daily", quantity, null, element); env.Journals.AddRange(fxJournals); } if (taxLotStatus.Quantity != 0.0) { if (env.ValueDate.Equals(new DateTime(2019, 12, 17))) { } if (element.TradeDate != env.ValueDate) { // Has to happen for every day var fxJournalsForInvestmentAtCost = FxPosting.CreateFx( env, CommonRules.GetFXMarkToMarketAccountType(element, "FX MARKET TO MARKET ON STOCK COST"), "Change in unrealized due to fx on original Cost", "daily", quantity, taxLotStatus, element); env.Journals.AddRange(fxJournalsForInvestmentAtCost); new FxPosting().CreateFxUnsettled(env, element); } } } }