示例#1
0
        /// <summary>
        /// Recursively calculates proposed orders for a sector.
        /// </summary>
        /// <param name="sector">Gives the current sector (sector) for the calculation.</param>
        private static void RecurseSectors(RemoteBatch remoteBatch, RemoteTransaction remoteTransaction, ClientMarketData.ModelRow modelRow,
                                           AppraisalSet.SectorRow driverSector, decimal actualSectorMarketValue, decimal targetSectorMarketValue)
        {
            // The main idea here is to keep the ratio of the security to the sector constant, while changing the market
            // value of the sector.  Scan each of the securities belonging to this sector.
            foreach (AppraisalSet.ObjectTreeRow objectTreeRow in
                     driverSector.ObjectRow.GetObjectTreeRowsByFKObjectObjectTreeParentId())
            {
                // Cycle through each of the securities in the sector.  We're going to keep the ratio of the security the
                // same as we target a different sector total.
                foreach (AppraisalSet.SecurityRow driverSecurity in
                         objectTreeRow.ObjectRowByFKObjectObjectTreeChildId.GetSecurityRows())
                {
                    foreach (AppraisalSet.PositionRow driverPosition in driverSecurity.GetPositionRows())
                    {
                        // We need to reference the security record for calculating proposed orders and the market value
                        // of the trade.
                        ClientMarketData.SecurityRow securityRow =
                            ClientMarketData.Security.FindBySecurityId(driverSecurity.SecurityId);

                        // In this rebalancing operation, the cash balance is dependant on the securities bought and
                        // sold.  When stocks are bought or sold below, they will impact the underlying currency.  A cash
                        // target can be reached by setting all the other percentages up properly.  As long as the total
                        // percentage in a model is 100%, the proper cash target will be calculated.  We don't have to do
                        // anything with this asset type.
                        if (securityRow.SecurityTypeCode == SecurityType.Currency)
                        {
                            continue;
                        }

                        // The ratio of the security within the sector will stay constant, even though the sector may
                        // increase or decrease with the target in the model.  Note that there's only one account in the
                        // 'Accounts' table of the driver because this is a 'Wrap' operation.
                        foreach (AppraisalSet.AccountRow driverAccount in driverPosition.GetAccountRows())
                        {
                            // Find the account associated with the driver record.
                            ClientMarketData.AccountRow accountRow =
                                ClientMarketData.Account.FindByAccountId(driverAccount.AccountId);

                            // The market value of all the securities are normalized to the base currency of the account
                            // so they can be aggregated.
                            ClientMarketData.CurrencyRow currencyRow =
                                ClientMarketData.Currency.FindByCurrencyId(accountRow.CurrencyId);

                            // Sector rebalancing keeps the percentage of a security within the sector constant.  Only the
                            // overall percentage of the sector with respect to the NAV changes.  The first step in this
                            // rebalancing operation is to calculate the market value of the given position.
                            decimal actualPositionMarketValue = MarketValue.Calculate(currencyRow, accountRow,
                                                                                      securityRow, driverPosition.PositionTypeCode, MarketValueFlags.EntirePosition);

                            // The target market value operation keeps the percentage of the position constant while
                            // changing the overall sector percentage.
                            decimal targetPositionMarketValue = (actualSectorMarketValue == 0) ? 0.0M :
                                                                actualPositionMarketValue * targetSectorMarketValue / actualSectorMarketValue;

                            // Calculate the market value of an order that will achieve the target.  Note that we're not
                            // including the existing proposed orders in the market value, but we did include them when
                            // calculating the account's market value.  This allows us to put in what-if orders that will
                            // impact the market value before we do the rebalancing.
                            decimal proposedMarketValue = targetPositionMarketValue - MarketValue.Calculate(currencyRow,
                                                                                                            accountRow, securityRow, driverPosition.PositionTypeCode,
                                                                                                            MarketValueFlags.ExcludeProposedOrder);

                            // Calculate the quantity needed to hit the target market value and round it according to the
                            // model.  Note that the market values and prices are all denominated in the currency of the
                            // parent account.  Also note the quantityFactor is needed for the proper quantity
                            // calculation.
                            decimal proposedQuantity = proposedMarketValue /
                                                       (Price.Security(currencyRow, securityRow) * securityRow.QuantityFactor);

                            // If we have an equity, round to the model's lot size.
                            if (securityRow.SecurityTypeCode == SecurityType.Equity)
                            {
                                proposedQuantity = Math.Round(proposedQuantity / modelRow.EquityRounding, 0) *
                                                   modelRow.EquityRounding;
                            }

                            // A debt generally needs to be rounded to face.
                            if (securityRow.SecurityTypeCode == SecurityType.Debt)
                            {
                                proposedQuantity = Math.Round(proposedQuantity / modelRow.DebtRounding, 0) *
                                                   modelRow.DebtRounding;
                            }

                            // Have the OrderForm object construct an order based on the quantity we've calcuated
                            // from the market value.  This will fill in the defaults for the order and translate the
                            // signed quantities into transaction codes.
                            ProposedOrder.Create(remoteBatch, remoteTransaction, accountRow, securityRow,
                                                 driverAccount.PositionTypeCode, proposedQuantity);
                        }
                    }
                }

                // Recurse into each of the sub-sectors.  This allows us to rebalance with any number of levels to the
                // hierarchy.  Eventually, we will run across a sector with security positions in it and end up doing some
                // real work.
                foreach (AppraisalSet.SectorRow childSector in objectTreeRow.ObjectRowByFKObjectObjectTreeChildId.GetSectorRows())
                {
                    SectorWrap.RecurseSectors(remoteBatch, remoteTransaction, modelRow, childSector, actualSectorMarketValue, targetSectorMarketValue);
                }
            }
        }
示例#2
0
        /// <summary>
        /// Recursively calculates proposed orders for a sector.
        /// </summary>
        /// <param name="sector">Gives the current sector (sector) for the calculation.</param>
        private static void RecurseSectors(RemoteBatch remoteBatch, RemoteTransaction remoteTransaction,
                                           ClientMarketData.CurrencyRow currencyRow, ClientMarketData.ModelRow modelRow, AppraisalSet.ObjectRow driverObject,
                                           decimal actualSectorMarketValue, decimal targetSectorMarketValue)
        {
            // Run through each of the positions in the sector and calculate the current percentage of the position within
            // the sector.  We're going to keep this percentage as we rebalance to the new sector market value.
            foreach (AppraisalSet.SecurityRow driverSecurity in driverObject.GetSecurityRows())
            {
                foreach (AppraisalSet.PositionRow driverPosition in driverSecurity.GetPositionRows())
                {
                    // We need to know what kind of security we're dealing with when calculating market values and quantities
                    // below.
                    ClientMarketData.SecurityRow securityRow =
                        ClientMarketData.Security.FindBySecurityId(driverSecurity.SecurityId);

                    // In this rebalancing operation, the cash balance is dependant on the securities bought and sold.  When
                    // stocks are bought or sold below, they will impact the underlying currency.  We can not balance to a
                    // currency target directly.
                    if (securityRow.SecurityTypeCode == SecurityType.Currency)
                    {
                        continue;
                    }

                    // Calculate the proposed orders for each account.  The fraction of the security within the sector will
                    // stay the same, even though the sector may increase or decrease with respect to the total market value.
                    foreach (AppraisalSet.AccountRow driverAccount in driverPosition.GetAccountRows())
                    {
                        // The underlying currency is needed for the market value calculations.
                        ClientMarketData.AccountRow accountRow = ClientMarketData.Account.FindByAccountId(driverAccount.AccountId);

                        // Sector rebalancing keeps the percentage of a security within the sector constant.  Only the overall
                        // percentage of the sector with respect to the NAV changes.  To accomplish this, we first calculate
                        // the percentage of the security within the sector before we rebalance the sector.
                        decimal actualPositionMarketValue = MarketValue.Calculate(currencyRow,
                                                                                  accountRow, securityRow, driverPosition.PositionTypeCode,
                                                                                  MarketValueFlags.EntirePosition);

                        // Calculate the target market value as a percentage of the entire sector (use zero if the sector has
                        // no market value to prevent divide by zero errors).
                        decimal targetPositionMarketValue = (actualSectorMarketValue == 0) ? 0.0M :
                                                            actualPositionMarketValue * targetSectorMarketValue / actualSectorMarketValue;

                        // The target proposed orders market value keeps the percentage of the position constant while
                        // changing the overall sector percentage.
                        decimal proposedMarketValue = targetPositionMarketValue - MarketValue.Calculate(currencyRow,
                                                                                                        accountRow, securityRow, driverPosition.PositionTypeCode,
                                                                                                        MarketValueFlags.ExcludeProposedOrder);

                        // Calculate the quantity needed to hit the target market value and round it according to the
                        // model.  Note that the market values and prices are all denominated in the currency of the
                        // parent account.  Also note the quantityFactor is needed for the proper quantity calculation.
                        decimal proposedQuantity = proposedMarketValue / (Price.Security(currencyRow, securityRow) *
                                                                          securityRow.PriceFactor * securityRow.QuantityFactor);

                        // If we have an equity, round to the model's lot size.
                        if (securityRow.SecurityTypeCode == SecurityType.Equity)
                        {
                            proposedQuantity = Math.Round(proposedQuantity / modelRow.EquityRounding, 0) *
                                               modelRow.EquityRounding;
                        }

                        // A debt generally needs to be rounded to face.
                        if (securityRow.SecurityTypeCode == SecurityType.Debt)
                        {
                            proposedQuantity = Math.Round(proposedQuantity / modelRow.DebtRounding, 0) *
                                               modelRow.DebtRounding;
                        }

                        // Have the Order Form Builder object construct an order based on the quantity we've calcuated from
                        // the market value.  This method will fill in the defaults needed for a complete proposed order.
                        ProposedOrder.Create(remoteBatch, remoteTransaction, accountRow, securityRow,
                                             driverAccount.PositionTypeCode, proposedQuantity);
                    }
                }
            }

            // Recurse into each of the sub-sectors.  This allows us to rebalance with any number of levels to the
            // hierarchy.  Eventually, we will run across a sector with security positions in it and end up doing some
            // real work.
            foreach (AppraisalSet.ObjectTreeRow driverTree in
                     driverObject.GetObjectTreeRowsByFKObjectObjectTreeParentId())
            {
                SectorMerge.RecurseSectors(remoteBatch, remoteTransaction, currencyRow, modelRow,
                                           driverTree.ObjectRowByFKObjectObjectTreeChildId, actualSectorMarketValue,
                                           targetSectorMarketValue);
            }
        }
示例#3
0
        /// <summary>
        /// Recursively rebalances an account and all it's children.
        /// </summary>
        /// <param name="accountRow">The parent account to be rebalanced.</param>
        private static void RecurseAccounts(RemoteBatch remoteBatch, RemoteTransaction remoteTransaction,
                                            AppraisalSet appraisalSet, ClientMarketData.AccountRow accountRow, ClientMarketData.ModelRow modelRow)
        {
            // The base currency of the account is used to cacluate market values.
            ClientMarketData.CurrencyRow currencyRow = ClientMarketData.Currency.FindByCurrencyId(accountRow.CurrencyId);

            // Calculate the total market value for the appraisal.  This will be the denominator in all calculations involving
            // portfolio percentages.
            decimal accountMarketValue = MarketValue.Calculate(currencyRow, accountRow, MarketValueFlags.EntirePosition);

            // Cycle through all the positions of the appraisal using the current account and calculate the size and direction of
            // the trade needed to bring it to the model's target percent.
            foreach (AppraisalSet.SecurityRow driverSecurity in appraisalSet.Security)
            {
                // We need to reference the security row in the ClientMarketData to price this item.
                ClientMarketData.SecurityRow securityRow = ClientMarketData.Security.FindBySecurityId(driverSecurity.SecurityId);

                // In this rebalancing operation, the cash balance is dependant on the securities bought and sold. The assumption
                // is made that we won't implicitly add or remove cash to accomplish the reblancing operation. When stocks are
                // bought or sold below, they will impact the underlying currency.  A cash target can be reached by setting all the
                // other percentages up properly.  As long as the total percentage in a model is 100%, the proper cash target will
                // be calculated.  We don't have to do anything with this asset type.
                if (securityRow.SecurityTypeCode == SecurityType.Currency)
                {
                    continue;
                }

                // This section will calculate the difference in between the actual and target market values for each
                // position and create orders that will bring the account to the targeted percentages.
                foreach (AppraisalSet.PositionRow driverPosition in driverSecurity.GetPositionRows())
                {
                    // Calculate the proposed quantity needed to bring this asset/account combination to the percentage given by
                    // the model.  First, find the target percent.  If it's not there, we assume a target of zero (meaning sell all
                    // holdings).
                    ClientMarketData.PositionTargetRow positionTargetRow =
                        ClientMarketData.PositionTarget.FindByModelIdSecurityIdPositionTypeCode(modelRow.ModelId,
                                                                                                securityRow.SecurityId, driverPosition.PositionTypeCode);
                    decimal targetPositionPercent = positionTargetRow == null ? 0.0M : positionTargetRow.Percent;

                    // The market value of this trade will be the target market value less the current market value of
                    // this position (without including the existing proposed orders in the current market value
                    // calculation).
                    decimal targetPositionMarketValue = targetPositionPercent * accountMarketValue;
                    decimal actualPositionMarketValue = MarketValue.Calculate(currencyRow, accountRow, securityRow,
                                                                              driverPosition.PositionTypeCode, MarketValueFlags.ExcludeProposedOrder);
                    decimal proposedMarketValue = targetPositionMarketValue - actualPositionMarketValue;

                    // Calculate the quantity needed to hit the target market value and round it according to the model. Note that
                    // the market values and prices are all denominated in the currency of the parent account. Also note the
                    // quantityFactor is needed for the proper quantity calculation.
                    decimal price            = Price.Security(currencyRow, securityRow);
                    decimal proposedQuantity = price == 0.0M ? 0.0M : proposedMarketValue / (price * securityRow.QuantityFactor);

                    // If we have an equity, round to the model's lot size.  Common values are 100 and 1.
                    if (securityRow.SecurityTypeCode == SecurityType.Equity)
                    {
                        proposedQuantity = Math.Round(proposedQuantity / modelRow.EquityRounding, 0) * modelRow.EquityRounding;
                    }

                    // A debt generally needs to be rounded to face.
                    if (securityRow.SecurityTypeCode == SecurityType.Debt)
                    {
                        proposedQuantity = Math.Round(proposedQuantity / modelRow.DebtRounding, 0) * modelRow.DebtRounding;
                    }

                    // Have the Order Form Builder object construct an order based on the new proposed quantity.  This method will
                    // fill in the defaults needed for a complete Proposed Order.  It will also create an deposit or widthdrawal
                    // from an account to cover the transaction.
                    ProposedOrder.Create(remoteBatch, remoteTransaction, accountRow, securityRow, driverPosition.PositionTypeCode,
                                         proposedQuantity);
                }
            }

            // Now that we've rebalanced the parent account, cycle through all the children accounts and rebalance them.
            foreach (ClientMarketData.ObjectTreeRow objectTreeRow in
                     accountRow.ObjectRow.GetObjectTreeRowsByFKObjectObjectTreeParentId())
            {
                foreach (ClientMarketData.AccountRow childAccount in
                         objectTreeRow.ObjectRowByFKObjectObjectTreeChildId.GetAccountRows())
                {
                    Security.RecurseAccounts(remoteBatch, remoteTransaction, appraisalSet, childAccount, modelRow);
                }
            }
        }
示例#4
0
        /// <summary>
        /// Fills the OrderForm table with instructions to create, delete or update proposed orders.
        /// </summary>
        /// <param name="accountId">Identifiers the destination account of the proposed order.</param>
        /// <param name="securityId">Identifies the security being trade.</param>
        /// <param name="positionTypeCode">Identifies the long or short position of the trade.</param>
        /// <param name="settlementId"></param>
        /// <param name="proposedQuantity">The signed (relative) quantity of the trade.</param>
        public static void Create(RemoteBatch remoteBatch, RemoteTransaction remoteTransaction,
                                  ClientMarketData.AccountRow accountRow, ClientMarketData.SecurityRow securityRow, int positionTypeCode,
                                  decimal proposedQuantity)
        {
            // If the proposed quantity is to be zero, we'll delete all proposed orders for this position in the parent and
            // descendant accounts.  Otherwise, a command batch will be created to clear any child proposed orders and create or
            // update a proposed order for the parent account.
            if (proposedQuantity == 0.0M)
            {
                ProposedOrder.Delete(remoteBatch, remoteTransaction, accountRow, securityRow, positionTypeCode);
            }
            else
            {
                // The strategy here is to cycle through all the existing proposed orders looking for any that match the account
                // id, security id and position type of the new order.  If none is found, we create a new order. If one is found,
                // we modify it for the new quantity.  Any additional proposed orders are deleted.  This flag lets us know if any
                // existing proposed orders match the position attributes.
                bool firstTime = true;

                // Cycle through each of the proposed orders in the given account looking for a matching position.
                object[] key = new object[] { accountRow.AccountId, securityRow.SecurityId, positionTypeCode };
                foreach (DataRowView dataRowView in ClientMarketData.ProposedOrder.UKProposedOrderAccountIdSecurityIdPositionTypeCode.FindRows(key))
                {
                    // This is used to reference the current proposed order that matches the position criteria.
                    ClientMarketData.ProposedOrderRow parentProposedOrderRow = (ClientMarketData.ProposedOrderRow)dataRowView.Row;

                    // This check is provided for currency-like assets.  There may be many proposed orders for currency
                    // transactions that are used to settle other trades.  The user can also enter currency orders directly into
                    // the appraisal.  Any manual deposits or withdrawls should not impact settlement orders.  This check will skip
                    // any trade that is linked to another order.
                    if (Shadows.Quasar.Common.Relationship.IsChildProposedOrder(parentProposedOrderRow))
                    {
                        continue;
                    }

                    // Recycle the first proposed order that matches the position criteria.  Any additional proposed orders for the
                    // same account, security, position type will be deleted.
                    if (firstTime)
                    {
                        // Any proposed orders found after this one will be deleted.  This variable will also indicate that an
                        // existing proposed order was recycled.  After the loop is run on this position, a new order will be
                        // created if an existing order couldn't be recycled.
                        firstTime = false;

                        // Create the command to update this proposed order.
                        Update(remoteBatch, remoteTransaction, parentProposedOrderRow, proposedQuantity);
                    }
                    else
                    {
                        // Any order that isn't recycled is considered to be redundant.  That is, this order has been superceded by
                        // the recycled order.  Clearing any redundant orders makes the operation more intuitive: the user knows
                        // that the only order on the books is the one they entered.  They don't have to worry about artifacts from
                        // other operations.
                        Delete(remoteBatch, remoteTransaction, parentProposedOrderRow);
                    }
                }

                // This will create a new proposed order if an existing one couldn't be found above for recycling.
                if (firstTime == true)
                {
                    Insert(remoteBatch, remoteTransaction, accountRow, securityRow, positionTypeCode, proposedQuantity);
                }
            }
        }