コード例 #1
0
        public void TradeDateEvent(PostingEngineEnvironment env, Transaction element)
        {
            double fxrate = 1.0;

            double multiplier = 1.0;

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

            // 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();

            if (element.IsBuy() || element.IsShort())
            {
                var t1 = env.GenerateOpenTaxLot(element, fxrate);

                if (element.Quantity == 0)
                {
                    // TODO: Need to review this as we need to see if there is a parent, and what the parents actuall is
                    return;
                }

                //tl.Save(env.Connection, env.Transaction);
            }
            else if (element.IsSell() || element.IsCover())
            {
                // Get Matching Lots
                var openLots = env.Methodology.GetOpenLots(env, element, element.Quantity);

                if (openLots.Count() == 0)
                {
                    var t1 = env.GenerateOpenTaxLot(element, fxrate);
                    // Whats going on here?
                    // We are skipping anything that does not get an OpenLot
                    env.AddMessage($"There should be for a sell {element.Symbol} have at least one open lot, non found");
                }
                else
                {
                    var workingQuantity = element.Quantity;

                    foreach (var lot in openLots)
                    {
                        if (workingQuantity == 0)
                        {
                            break;
                        }

                        if (!env.TaxLotStatus.ContainsKey(lot.Trade.LpOrderId))
                        {
                            // TODO: For this open lot there should be a corresponding open to
                            continue;
                        }

                        var taxlotStatus = env.TaxLotStatus[lot.Trade.LpOrderId];
                        if (taxlotStatus != null && taxlotStatus.Quantity != 0 && !taxlotStatus.Status.ToLowerInvariant().Equals("closed"))
                        {
                            // Does the open Lot fully fullfill the quantity ?
                            if (Math.Abs(taxlotStatus.Quantity) >= Math.Abs(workingQuantity))
                            {
                                var taxlot = CommonRules.RelieveTaxLot(env, lot, element, workingQuantity, true);

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

                                CommonRules.GenerateCloseOutPostings(env, lot, taxlot, element, taxlotStatus, tradeAllocations[0].Fund);

                                break;
                            }
                            else
                            {
                                var taxlot = CommonRules.RelieveTaxLot(env, lot, element, taxlotStatus.Quantity * -1);

                                workingQuantity -= Math.Abs(taxlotStatus.Quantity);

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

                                taxlotStatus.Quantity = 0;
                                taxlotStatus.Status   = "Closed";
                            }
                        }
                    }
                }
            }
            else
            {
                // We have a Debit / Credit Dividends
            }
        }
コード例 #2
0
        /// <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 });
             */
        }