/// <summary> /// Recurively copies the outline of the sector from the data model into the AppraisalSet. /// </summary> /// <param name="childSecurity">The end branch or leaf of the tree structure. The sector outline is built from /// the security towards the classification scheme which is the root of the tree.</param> /// <remarks> /// Table locks needed: /// Read: Object /// Read: ObjectTree /// Read: Sector /// </remarks> private void BuildSector(DataModel.ObjectRow childObject) { // The child row in the driver tables will be needed below if we have to add a relationship to the driver. AppraisalSet.ObjectRow childDriver = this.Object.FindByObjectId(childObject.ObjectId); // We are going to look at each of the parents of the given security to see if it's a member of the security // classification scheme. Though there may be zero or many parents of any security or sector, there is only // one path to the classification scheme. Remember, this method searches from the top of the hierarchy tree // down to the root foreach (DataModel.ObjectTreeRow objectTreeRow in childObject.GetObjectTreeRowsByFKObjectObjectTreeChildId()) { foreach (DataModel.SectorRow parentSector in objectTreeRow.ObjectRowByFKObjectObjectTreeParentId.GetSectorRows()) { // Find the parent element in the driver tables. If it doesn't exist, we're going to add it before // adding the parent/child relationship. AppraisalSet.ObjectRow parentDriver = this.Object.FindByObjectId(parentSector.SectorId); // Check to see if the parent already exists in the hierarchy. If it doesn't exist and the parent is // part of the classification scheme, we're going to add the parent and the relationship to the // outline. If the parent does exist, then we'll check to see if the relationship should be added. if (parentDriver == null) { // Make sure that the parent security is part of the classification scheme of the document before // adding it. This keeps fragments from other scheme from showing up in the driver tables. if (IsObjectInScheme(parentSector.ObjectRow)) { // Add the parent sector to the outline. parentDriver = this.Object.AddObjectRow(parentSector.SectorId); this.Sector.AddSectorRow(parentDriver); // Add the tree branch into the outline. this.ObjectTree.AddObjectTreeRow(parentDriver, childDriver); // Recurse down the tree until every branch of this hierarchy leading up to this security is // included in the document. BuildSector(parentSector.ObjectRow); BuildScheme(parentSector.ObjectRow); } } else { // If the sector already is part of the hierarchy, check to see if the relationship has is part of // the outline also. If not, add it. if (this.ObjectTree.FindByParentIdChildId(parentSector.SectorId, childObject.ObjectId) == null) { this.ObjectTree.AddObjectTreeRow(parentDriver, childDriver); } } } } }
/// <summary> /// Copies the outline of a security position from the data model into the AppraisalSet. /// </summary> /// <param name="AccountId">AccountId of the position to search through.</param> /// <param name="SecurityId">SecurityId of the position to search through.</param> /// <param name="PositionTypeCode">Position Type Code of the position to search through.</param> /// <remarks> /// Table locks needed: /// Read: Security /// </remarks> protected void BuildSecurity(int AccountId, int SecurityId, int PositionTypeCode) { // See if the given security exists already in the table of security. If this is the first time we've // encountered this security, we need to add it to the driver tables and then recursively search the hierarchy // and add every parent sector all the way up to the security classification scheme. If we've run across it // already, we don't need to do anything related to the security. AppraisalSet.SecurityRow driverSecurity = this.Security.FindBySecurityId(SecurityId); if (driverSecurity == null) { // The AppraisalSet structure mirrors the structure of the MarketData. We have a common 'object' table that // all object can use to navigate the tree structure. When adding a new element to the data structure, // we need to add the object first to maintain integrity, then the security can be added. AppraisalSet.ObjectRow objectRow = this.Object.AddObjectRow(SecurityId); driverSecurity = this.Security.AddSecurityRow(objectRow); // Recursively search the hierarchy all the way up to the security classification scheme. This will add // any elements of the hierarchy that are not already part of the outline. Note that we first check to // see if the security belongs to the given security scheme before building the links. This saves us from // having unused fragments of other security scheme in the outline. This is useful when checking for // unclassified security. DataModel.SecurityRow securityRow = DataModel.Security.FindBySecurityId(SecurityId); if (IsObjectInScheme(securityRow.ObjectRow)) { BuildSector(securityRow.ObjectRow); BuildScheme(securityRow.ObjectRow); } } // At this point, we know that the security and all the sector have been added to the outline. Check to see // if the position -- that is, the combination of security and whether we own it or have borrowed it -- exist // in the outline. Add the combination if it doesn't. AppraisalSet.PositionRow positionRow = this.Position.FindBySecurityIdPositionTypeCode(SecurityId, PositionTypeCode); if (positionRow == null) { positionRow = this.Position.AddPositionRow(driverSecurity, PositionTypeCode); } // Finally, at the bottom of the list, is the account level information. This operation insures that only distinct account/position combinations // appear in the document. This is very useful if the same account were to appear in different groups. AppraisalSet.AccountRow driverAccount = this.Account.FindByAccountIdSecurityIdPositionTypeCode(AccountId, SecurityId, PositionTypeCode); if (driverAccount == null) { driverAccount = this.Account.AddAccountRow(AccountId, SecurityId, PositionTypeCode); } }
/// <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); } }
/// <summary> /// Recusively builds the XML document from the document outline. /// </summary> /// <param name="parentElement">The parent XML element the node being built.</param> /// <param name="parentSecurity">The parent security.</param> private void BuildDocument(CommonElement parentElement, AppraisalSet.ObjectRow parentObject) { // The code below will test to see if the current node is a sector or security, then create the appropriate // element. The outline doesn't have the full information about the securities, so we need to get a record // into the data model that can reference the security master. ClientMarketData.ObjectRow childObject = ClientMarketData.Object.FindByObjectId(parentObject.ObjectId); // Attach the sectors to this level of the document. foreach (ClientMarketData.SectorRow sectorRow in childObject.GetSectorRows()) { // Create the new sector element and attach it to the document. SectorElement sectorElement = new SectorElement(this, sectorRow); parentElement.InsertBySortOrder(sectorElement); // Recurse down into the children securities looking for more sectors or securities to attach. foreach (AppraisalSet.ObjectTreeRow objectTreeRow in parentObject.GetObjectTreeRowsByFKObjectObjectTreeParentId()) { BuildDocument(sectorElement, objectTreeRow.ObjectRowByFKObjectObjectTreeChildId); } } // Attach the securities to this level of the document. foreach (ClientMarketData.SecurityRow securityRow in childObject.GetSecurityRows()) { // Attach long and short Debts to this level of the document. foreach (ClientMarketData.DebtRow debtRow in securityRow.GetDebtRowsByFKSecurityDebtDebtId()) { foreach (AppraisalSet.SecurityRow driverSecurity in parentObject.GetSecurityRows()) { foreach (AppraisalSet.PositionRow driverPosition in driverSecurity.GetPositionRows()) { parentElement.InsertByName(new DebtElement(this, debtRow, driverPosition)); } } } // Attach long and short Currencies to this level of the document. foreach (ClientMarketData.CurrencyRow currencyRow in securityRow.GetCurrencyRows()) { foreach (AppraisalSet.SecurityRow driverSecurity in parentObject.GetSecurityRows()) { foreach (AppraisalSet.PositionRow driverPosition in driverSecurity.GetPositionRows()) { parentElement.InsertByName(new CurrencyElement(this, currencyRow, driverPosition)); } } } // Attach long and short Equities to this level of the document. foreach (ClientMarketData.EquityRow equityRow in securityRow.GetEquityRowsByFKSecurityEquityEquityId()) { foreach (AppraisalSet.SecurityRow driverSecurity in parentObject.GetSecurityRows()) { foreach (AppraisalSet.PositionRow driverPosition in driverSecurity.GetPositionRows()) { parentElement.InsertByName(new EquityElement(this, equityRow, driverPosition)); } } } } }