Ejemplo n.º 1
0
        /// <summary>
        /// Calcualte the Unrealized Pnl for this Tax lot
        /// </summary>
        /// <param name="env"></param>
        /// <returns></returns>
        public static double CalculateUnrealizedPnl(PostingEngineEnvironment env, TaxLotStatus taxLotStatus, double residualQuantity = 0, double endPrice = 0)
        {
            double multiplier = 1.0;

            if (env.SecurityDetails.ContainsKey(taxLotStatus.Trade.BloombergCode))
            {
                multiplier = env.SecurityDetails[taxLotStatus.Trade.BloombergCode].Multiplier;
            }

            double fxrate = 1.0;

            // Lets get fx rate if needed
            if (!taxLotStatus.Trade.SettleCurrency.Equals(env.BaseCurrency))
            {
                fxrate = Convert.ToDouble(FxRates.Find(env.ValueDate, taxLotStatus.Trade.SettleCurrency).Rate);
            }

            var eodPrice     = 0.0;
            var prevEodPrice = 0.0;

            if (env.ValueDate == taxLotStatus.Trade.TradeDate)
            {
                prevEodPrice = taxLotStatus.Trade.SettleNetPrice;
                var eodMarketPrice = MarketPrices.GetPrice(env, env.ValueDate, taxLotStatus.Trade);

                if (!eodMarketPrice.Valid)
                {
                    env.AddMessage(eodMarketPrice.Error);
                }

                eodPrice = eodMarketPrice.Price;
            }
            else
            {
                prevEodPrice = MarketPrices.GetPrice(env, env.PreviousValueDate, taxLotStatus.Trade).Price;
                eodPrice     = MarketPrices.GetPrice(env, env.ValueDate, taxLotStatus.Trade).Price;
            }

            eodPrice = endPrice != 0 ? endPrice : eodPrice;

            // Use residual Quantity if specified
            var quantity = residualQuantity != 0.0 ? residualQuantity : taxLotStatus.Quantity;

            var priceDiff = (eodPrice - prevEodPrice);

            var unrealizedPnl = priceDiff * quantity;

            return(unrealizedPnl * fxrate * multiplier);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Relieves the passed TaxLostStatus, this should only be used for FORWARDS etc that expire
        /// </summary>
        /// <param name="env">Environment</param>
        /// <param name="lot">The Tax Lot to relieve</param>
        /// <param name="trade">The current trade</param>
        /// <param name="quantity">Quantity to relieve</param>
        /// <param name="fxrate">Appropriate fxrate</param>
        internal static TaxLot RelieveTaxLot(PostingEngineEnvironment env, Transaction taxLotToRelieve, Transaction trade, double quantity, bool reverse = false)
        {
            var SettleNetPrice = trade.SettleNetPrice;

            if (taxLotToRelieve.LpOrderId.Equals(trade.LpOrderId))
            {
                // Same, so we are dealing with the same trade, so we are backing out the same trade
                SettleNetPrice = MarketPrices.GetPrice(env, trade.SettleDate, trade).Price;
            }

            var prevFxRate = FxRates.Find(taxLotToRelieve.TradeDate, taxLotToRelieve.SettleCurrency).Rate;

            var investmentAtCost = quantity * taxLotToRelieve.SettleNetPrice * prevFxRate;

            if (reverse)
            {
                investmentAtCost = investmentAtCost * -1;
            }

            var tl = new TaxLot
            {
                Trade            = trade,
                TradeDate        = trade.TradeDate,
                InvestmentAtCost = investmentAtCost, // Needs to be the Investment Cost that we are relieving from the Tax
                BusinessDate     = env.ValueDate,
                OpeningLotId     = taxLotToRelieve.LpOrderId,
                ClosingLotId     = trade.LpOrderId,
                TradePrice       = taxLotToRelieve.SettleNetPrice,
                CostBasis        = SettleNetPrice,
                Quantity         = quantity
            };

            CalculateRealizedPnl(env, tl);

            tl.Save(env.Connection, env.Transaction);

            return(tl);
        }
Ejemplo n.º 3
0
        /// <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);
                    }
                }
            }
        }
        /// <summary>
        /// Generate all of the journal entries we need for reduction / closeout of a tax lot
        /// </summary>
        /// <param name="env"></param>
        /// <param name="lot"></param>
        /// <param name="taxlotStatus"></param>
        /// <param name="element"></param>
        /// <param name="workingQuantity"></param>
        /// <param name="fxrate"></param>
        /// <param name="multiplier"></param>
        private void GenerateJournals(PostingEngineEnvironment env, TaxLotDetail lot, TaxLotStatus taxlotStatus, Transaction element, double workingQuantity, double fxrate, double multiplier)
        {
            var buyTrade = env.FindTrade(lot.Trade.LpOrderId);

            var taxlot = CommonRules.RelieveTaxLot(env, lot, element, workingQuantity, true);

            // 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", workingQuantity, taxlotStatus, buyTrade);

            env.Journals.AddRange(fxJournalsForInvestmentAtCost);

            taxlotStatus.Quantity += workingQuantity;
            if (taxlotStatus.Quantity == 0)
            {
                taxlotStatus.Status = "Closed";
            }
            else
            {
                taxlotStatus.Status = "Partially Closed";
            }

            if (taxlotStatus.Quantity == 0.0)
            {
                // Is this really needed, as if the tax lot is zero then should not generate any additional unrealized pnl
                //GenerateDailyUnrealized(env, taxlotStatus, element, workingQuantity * -1, fxrate);
            }

            var eodPrice = MarketPrices.GetPrice(env, env.PreviousValueDate, buyTrade).Price;

            // Calculate the unrealized Backout PNL for the created Tax Lot
            var unrealizedPnl = Math.Abs(taxlot.Quantity) * (eodPrice - buyTrade.SettleNetPrice) * multiplier * fxrate;

            unrealizedPnl *= CommonRules.DetermineSign(element);

            // Need to backout the Unrealized PNL here, as we are reducing the position of the TaxLot
            CommonRules.ReverseUnrealizedPnl(
                env,
                buyTrade,
                element,
                unrealizedPnl * -1,
                buyTrade.SettleNetPrice,
                element.SettleNetPrice,
                fxrate);

            // Original FxRate
            var changeDueToFx = fxrate - taxlotStatus.FxRate;
            // Original Trade Price
            var changeInRealizedPnlDueToFx   = changeDueToFx * (taxlot.TradePrice) * Math.Abs(taxlot.Quantity);
            var changeInUnRealizedPnlDueToFx = changeDueToFx * (taxlot.CostBasis - taxlot.TradePrice) * Math.Abs(taxlot.Quantity);

            CommonRules.PostRealizedPnl(
                env,
                buyTrade,
                taxlot.RealizedPnl,
                taxlot.TradePrice,
                taxlot.CostBasis,
                fxrate);

            if (fxrate != 1.0)
            {
                PostRealizedFxGain(env, buyTrade, changeInRealizedPnlDueToFx, taxlot.TradePrice, taxlot.CostBasis, changeDueToFx);
            }

            var fxChange = new FxPosting().CreateFxUnsettled(env, buyTrade);

            List <SqlParameter> sqlParams = new List <SqlParameter>();

            sqlParams.Add(new SqlParameter("@busDate", env.ValueDate));
            sqlParams.Add(new SqlParameter("@LpOrderId", lot.Trade.LpOrderId));

            var dataTable = new SqlHelper(env.ConnectionString).GetDataTables("ClosingTaxLot", CommandType.StoredProcedure, sqlParams.ToArray());

            var changeInUnRealized = 1.0;

            if (dataTable[0].Rows.Count > 0)
            {
                changeInUnRealized = Convert.ToDouble(dataTable[0].Rows[0][2]);
            }

            var changeInUnRealizedFx = 0.0;

            if (dataTable[1].Rows.Count > 0)
            {
                changeInUnRealizedFx = Convert.ToDouble(dataTable[1].Rows[0][2]);
            }

            if (changeInUnRealizedFx != 0.0)
            {
                var closeOut = changeInUnRealizedFx + fxChange;

                PostUnrealizedFxGain(env, buyTrade, closeOut, taxlot.TradePrice, taxlot.CostBasis, changeDueToFx);
            }

            var sumFxMarkToMarket = 0.0;

            if (dataTable[2].Rows.Count > 0)
            {
                sumFxMarkToMarket  = Convert.ToDouble(dataTable[2].Rows[0][2]);
                sumFxMarkToMarket += fxJournalsForInvestmentAtCost[0].Value;

                ReversePosting(env, "Change in unrealized due to fx on original Cost", CommonRules.GetFXMarkToMarketAccountType(element, "FX MARKET TO MARKET ON STOCK COST"), buyTrade, sumFxMarkToMarket);
            }


            var listOfFromTags = new List <Tag>
            {
                Tag.Find("SecurityType"),
                Tag.Find("CustodianCode")
            };

            /*
             * var markToMarketAccount = (buyTrade.IsShort() || buyTrade.IsCover()) ? "Mark to Market Shorts" : "Mark to Market Longs";
             *
             * var fromTo = new AccountUtils().GetAccounts(env, "CHANGE IN UNREALIZED GAIN/(LOSS)", markToMarketAccount, listOfFromTags, element);
             *
             * if (fxrate == 1.0)
             * {
             *  changeInUnRealized = Convert.ToDouble(taxlot.RealizedPnl) * -1;
             * }
             *
             * // Now Generate Entries for the trade that is drawing down on the taxLot
             * var fromJournal = new Journal(buyTrade)
             * {
             *  Account = fromTo.From,
             *  When = env.ValueDate,
             *
             *  CreditDebit = env.DebitOrCredit(fromTo.From, changeInUnRealized),
             *  Value = env.SignedValue(fromTo.From, fromTo.To, true, changeInUnRealized),
             *  Event = Event.UNREALIZED_PNL,
             *  Fund = env.GetFund(element),
             *
             *  StartPrice = taxlot.TradePrice,
             *  EndPrice = taxlot.CostBasis,
             *  FxRate = fxrate,
             * };
             *
             * var toJournal = new Journal(buyTrade)
             * {
             *  Account = fromTo.To,
             *  When = env.ValueDate,
             *
             *  CreditDebit = env.DebitOrCredit(fromTo.To, changeInUnRealized * -1),
             *  Value = env.SignedValue(fromTo.From, fromTo.To, false, changeInUnRealized),
             *  Event = Event.UNREALIZED_PNL,
             *  Fund = env.GetFund(element),
             *
             *  StartPrice = taxlot.TradePrice,
             *  EndPrice = taxlot.CostBasis,
             *  FxRate = fxrate,
             * };
             *
             * env.Journals.AddRange(new[] { fromJournal, toJournal });
             */
        }
Ejemplo n.º 6
0
        /// <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")
                    };

                    var split        = element.Symbol.Split(new char[] { '/', ' ' });
                    var baseCurrency = split[0];
                    var riskCurrency = split[1];

                    var eodPrice     = MarketPrices.GetPrice(env, env.ValueDate, element).Price;
                    var prevEodPrice = MarketPrices.GetPrice(env, env.PreviousValueDate, element).Price;

                    if (baseCurrency.Equals(env.BaseCurrency))
                    {
                        if (env.ValueDate == element.TradeDate)
                        {
                            prevEodPrice = element.SettleNetPrice;
                        }
                    }
                    else
                    {
                        if (env.ValueDate == element.TradeDate)
                        {
                            prevEodPrice = element.SettleNetPrice;
                        }
                    }

                    // we need to do this when there is no price for the trade from market data
                    if (prevEodPrice == 0.0)
                    {
                        prevEodPrice = element.SettleNetPrice;
                    }

                    if (eodPrice == 0.0)
                    {
                        eodPrice = element.SettleNetPrice;
                    }

                    // We have an open / partially closed tax lot so now need to calculate unrealized Pnl
                    var quantity = taxlot.Quantity;

                    var rateDiff = (eodPrice - prevEodPrice);

                    var unrealizedPnl = (rateDiff * quantity);

                    if (baseCurrency.Equals(env.BaseCurrency))
                    {
                        unrealizedPnl = unrealizedPnl / eodPrice;
                    }

                    var originalAccount = AccountUtils.GetDerivativeAccountType(unrealizedPnl);
                    var fromToAccounts  = new AccountUtils().GetAccounts(env, originalAccount, "Change in Unrealized Derivatives Contracts at Fair Value", 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      = rateDiff,
                        Value       = env.SignedValue(fromToAccounts.From, fromToAccounts.To, false, 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, true, unrealizedPnl),
                        CreditDebit = env.DebitOrCredit(fromToAccounts.To, unrealizedPnl),
                    };

                    env.Journals.AddRange(new[] { debit, credit });

                    if (element.LpOrderId.Equals("3bbf9793-d01a-4a08-b25c-448fd1777ef1"))
                    {
                    }

                    if (element.TradeDate != env.ValueDate && element.SettleDate >= env.ValueDate)
                    {
                        var fxJournals = FxPosting.CreateFx(
                            env,
                            "daily",
                            quantity, null, element);
                        env.Journals.AddRange(fxJournals);
                    }
                }
            }
            else
            {
                if (fxrate != 1.0)
                {
                    if (element.TradeDate != env.ValueDate && element.SettleDate >= env.ValueDate)
                    {
                        var fxJournals = FxPosting.CreateFx(
                            env,
                            "daily",
                            element.Quantity, null, element);
                        env.Journals.AddRange(fxJournals);
                    }
                }
            }
        }
Ejemplo n.º 7
0
        public void SettlementDateEvent(PostingEngineEnvironment env, Transaction element)
        {
            // On Settlement Date we backout the Tax Lot for FORWARDS
            if (env.TaxLotStatus.ContainsKey(element.LpOrderId))
            {
                var taxlotStatus = env.TaxLotStatus[element.LpOrderId];

                var split        = element.Symbol.Split(new char[] { '/', ' ' });
                var baseCurrency = split[0];
                var riskCurrency = split[1];

                var accountBuy = new AccountUtils().CreateAccount(atSettledCash, new List <string> {
                    element.SecurityType, element.CustodianCode, baseCurrency
                });
                var accountSell = new AccountUtils().CreateAccount(atSettledCash, new List <string> {
                    element.SecurityType, element.CustodianCode, riskCurrency
                });

                new AccountUtils().SaveAccountDetails(env, accountBuy);
                new AccountUtils().SaveAccountDetails(env, accountSell);

                var fxCurrency   = riskCurrency;
                var tradePrice   = taxlotStatus.TradePrice;
                var baseQuantity = element.Quantity;

                var eodPrice = MarketPrices.GetPrice(env, env.ValueDate, element).Price;
                var fxRate   = FxRates.Find(env.ValueDate, fxCurrency).Rate;

                var buyValue  = baseQuantity * tradePrice * fxRate;
                var sellValue = baseQuantity * eodPrice * fxRate;

                if (element.IsBuy()) // BUY
                {
                    var realizedPnl = sellValue - buyValue;

                    var debit = new Journal(accountBuy, Event.SETTLED_CASH, env.ValueDate)
                    {
                        Source     = element.LpOrderId,
                        Fund       = env.GetFund(element),
                        FxCurrency = baseCurrency,
                        Symbol     = element.Symbol,
                        SecurityId = element.SecurityId,
                        Quantity   = Convert.ToDouble(element.Quantity),

                        FxRate     = tradePrice,
                        StartPrice = tradePrice,
                        EndPrice   = eodPrice,

                        Value       = env.SignedValue(accountBuy, accountSell, true, buyValue),
                        CreditDebit = env.DebitOrCredit(accountBuy, buyValue),
                    };

                    var credit = new Journal(accountSell, Event.SETTLED_CASH, env.ValueDate)
                    {
                        Source     = element.LpOrderId,
                        Fund       = env.GetFund(element),
                        FxCurrency = riskCurrency,
                        Symbol     = element.Symbol,
                        SecurityId = element.SecurityId,
                        Quantity   = Convert.ToDouble(element.Quantity),

                        FxRate     = tradePrice,
                        StartPrice = 0,
                        EndPrice   = 0,

                        Value       = env.SignedValue(accountBuy, accountSell, true, sellValue * -1),
                        CreditDebit = env.DebitOrCredit(accountSell, sellValue),
                    };

                    env.Journals.AddRange(new[] { credit, debit });

                    var originalAccount = AccountUtils.GetDerivativeAccountType(realizedPnl);

                    // Realized Pnl to go along with the Settled Cash
                    CommonRules.GenerateJournalEntry(env, element, listOfTags, realizedAccountType, Event.REALIZED_PNL, realizedPnl);

                    CommonRules.GenerateJournalEntries(env, element, listOfTags, originalAccount, "Change in Unrealized Derivatives Contracts at Fair Value", realizedPnl * -1);
                }
                else // SELL
                {
                    var realizedPnl = buyValue - sellValue;

                    var debit = new Journal(accountBuy, Event.SETTLED_CASH, env.ValueDate)
                    {
                        Source     = element.LpOrderId,
                        Fund       = env.GetFund(element),
                        FxCurrency = baseCurrency,
                        Symbol     = element.Symbol,
                        SecurityId = element.SecurityId,
                        Quantity   = Convert.ToDouble(element.Quantity),

                        FxRate     = tradePrice,
                        StartPrice = 0,
                        EndPrice   = 0,

                        Value       = env.SignedValue(accountBuy, accountSell, true, sellValue),
                        CreditDebit = env.DebitOrCredit(accountBuy, element.Quantity),
                    };

                    var credit = new Journal(accountSell, Event.SETTLED_CASH, env.ValueDate)
                    {
                        Source     = element.LpOrderId,
                        Fund       = env.GetFund(element),
                        FxCurrency = riskCurrency,
                        Symbol     = element.Symbol,
                        SecurityId = element.SecurityId,
                        Quantity   = Convert.ToDouble(element.Quantity),

                        FxRate     = tradePrice,
                        StartPrice = 0,
                        EndPrice   = 0,

                        Value       = env.SignedValue(accountBuy, accountSell, true, buyValue * -1),
                        CreditDebit = env.DebitOrCredit(accountSell, element.Quantity),
                    };

                    env.Journals.AddRange(new[] { credit, debit });

                    var originalAccount = AccountUtils.GetDerivativeAccountType(realizedPnl);

                    // Realized Pnl to go along with the Settled Cash
                    CommonRules.GenerateJournalEntry(env, element, listOfTags, realizedAccountType, Event.REALIZED_PNL, realizedPnl);

                    CommonRules.GenerateJournalEntries(env, element, listOfTags, originalAccount, "Change in Unrealized Derivatives Contracts at Fair Value", realizedPnl * -1);
                }

                if (taxlotStatus.Quantity != 0)
                {
                    var buyTrade = env.FindTrade(taxlotStatus.OpenId);
                    var taxlot   = CommonRules.RelieveTaxLot(env, buyTrade, element, taxlotStatus.Quantity * -1, true);
                    taxlotStatus.Quantity = 0;
                    taxlotStatus.Status   = "Closed";
                }
            }
        }
Ejemplo n.º 8
0
        internal static void GenerateTradeDateJournals(PostingEngineEnvironment env, Transaction element)
        {
            double multiplier = 1.0;

            if (env.SecurityDetails.ContainsKey(element.BloombergCode))
            {
                multiplier = env.SecurityDetails[element.BloombergCode].Multiplier;
            }

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

            var tradeAllocations = env.Allocations.Where(i => i.LpOrderId == element.LpOrderId).ToList();

            // Retrieve Allocation Objects for this trade
            if (tradeAllocations.Count() > 2)
            {
                env.AddMessage($"#of allocations > 2 please investigate {element.LpOrderId}");
                return;
            }

            if (tradeAllocations.Count() == 2)
            {
                var debitEntry = tradeAllocations[0].Side == element.Side ? tradeAllocations[0] : tradeAllocations[1];
                if (debitEntry.Symbol.Equals("@CASHUSD"))
                {
                    env.AddMessage($"Unexpected Cash allocation please investigate {element.LpOrderId}");
                    return;
                }
            }

            var accountToFrom = GetFromToAccount(env, element);

            if (accountToFrom.To == null || accountToFrom.From == null)
            {
                env.AddMessage($"Unable to identify From/To accounts for trade {element.OrderSource} :: {element.Side}");
                return;
            }

            if (element.NetMoney != 0.0)
            {
                var moneyUSD = Math.Abs(element.NetMoney) * fxrate;

                // BUY -- Debit
                // SELL -- Credit

                if (element.IsSell() || element.IsCover())
                {
                    moneyUSD = moneyUSD * -1;
                }

                var eodPrice = MarketPrices.GetPrice(env, env.ValueDate, element).Price;

                var fromJournal = new Journal(element, accountToFrom.From, Event.TRADE_DATE, env.ValueDate)
                {
                    CreditDebit = env.DebitOrCredit(accountToFrom.From, moneyUSD),
                    Value       = env.SignedValue(accountToFrom.From, accountToFrom.To, true, moneyUSD),
                    FxRate      = fxrate,
                    StartPrice  = element.SettleNetPrice,
                    EndPrice    = eodPrice,
                    Fund        = env.GetFund(element),
                };

                var toJournal = new Journal(element, accountToFrom.To, Event.TRADE_DATE, env.ValueDate)
                {
                    FxRate      = fxrate,
                    CreditDebit = env.DebitOrCredit(accountToFrom.To, moneyUSD * -1),
                    Value       = env.SignedValue(accountToFrom.From, accountToFrom.To, false, moneyUSD),
                    StartPrice  = element.SettleNetPrice,
                    EndPrice    = eodPrice,
                    Fund        = env.GetFund(element),
                };

                env.Journals.AddRange(new[] { fromJournal, toJournal });
            }
        }
Ejemplo n.º 9
0
        internal static void GenerateCloseOutPostings(PostingEngineEnvironment env, TaxLotDetail lot, TaxLot taxlot, Transaction element, TaxLotStatus taxlotStatus, string fund)
        {
            double multiplier = 1.0;

            if (env.SecurityDetails.ContainsKey(element.BloombergCode))
            {
                multiplier = env.SecurityDetails[element.BloombergCode].Multiplier;
            }

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

            var prevPrice     = MarketPrices.GetPrice(env, env.PreviousValueDate, lot.Trade).Price;
            var unrealizedPnl = Math.Abs(taxlotStatus.Quantity) * (element.SettleNetPrice - prevPrice) * multiplier;

            unrealizedPnl = Math.Abs(unrealizedPnl) * CommonRules.DetermineSign(taxlotStatus.Trade);

            var buyTrade = env.FindTrade(lot.Trade.LpOrderId);

            ReverseUnrealizedPnl(
                env,
                buyTrade,
                element,
                unrealizedPnl,
                MarketPrices.GetPrice(env, env.PreviousValueDate, lot.Trade).Price,
                element.SettleNetPrice, fxrate);

            var PnL = taxlot.RealizedPnl;

            PostRealizedPnl(
                env,
                buyTrade,
                PnL,
                taxlot.TradePrice,
                taxlot.CostBasis, fxrate);

            var listOfFromTags = new List <Tag>
            {
                Tag.Find("SecurityType"),
                Tag.Find("CustodianCode")
            };

            Account fromAccount = null;
            Account toAccount   = null;

            if (element.IsDerivative())
            {
                return;
            }
            else
            {
                var accountType         = (buyTrade.IsShort() || buyTrade.IsCover()) ? "SHORT POSITIONS AT COST" : "LONG POSITIONS AT COST";
                var markToMarketAccount = (buyTrade.IsShort() || buyTrade.IsCover()) ? "Mark to Market Shorts" : "Mark to Market Longs";

                fromAccount = new AccountUtils().CreateAccount(AccountType.Find(accountType), listOfFromTags, element);
                toAccount   = new AccountUtils().CreateAccount(AccountType.Find(markToMarketAccount), listOfFromTags, element);
            }

            new AccountUtils().SaveAccountDetails(env, fromAccount);
            new AccountUtils().SaveAccountDetails(env, toAccount);

            // Now Generate Entries
            var fromJournal = new Journal(element)
            {
                Account     = fromAccount,
                CreditDebit = env.DebitOrCredit(fromAccount, PnL),
                When        = env.ValueDate,
                StartPrice  = taxlot.TradePrice,
                EndPrice    = taxlot.CostBasis,
                Value       = PnL,
                FxRate      = 1,
                Event       = Event.REALIZED_PNL,
                Fund        = env.GetFund(element),
            };

            var toJournal = new Journal(fromJournal)
            {
                Account     = toAccount,
                CreditDebit = env.DebitOrCredit(toAccount, PnL * -1),
                Value       = PnL * -1,
            };

            env.Journals.AddRange(new[] { fromJournal, toJournal });
        }