/// <summary> /// Constructs an AppraisalDocument. /// </summary> /// <param name="accountRow">A record containing the account or fund data.</param> /// <param name="modelRow">A record containing the model that is superimposed on the appraisal data for /// rebalancing.</param> public AppraisalDocument(ClientMarketData.AccountRow accountRow, ClientMarketData.ModelRow modelRow) { // Create a view of the proposed orders that makes it easy to aggregate by position. this.proposedOrderView = new DataView(ClientMarketData.ProposedOrder); this.proposedOrderView.Sort = "[AccountId], [SecurityId], [PositionTypeCode]"; // Create a view of the orders that makes it easy to aggregate by position. this.orderView = new DataView(ClientMarketData.Order); this.orderView.Sort = "[AccountId], [SecurityId], [PositionTypeCode]"; // Create a view of the allocations that makes it easy to aggregate by position. this.allocationView = new DataView(ClientMarketData.Allocation); this.allocationView.Sort = "[AccountId], [SecurityId], [PositionTypeCode]"; // This makes the account and model avaiable to the recursive methods. this.accountRow = accountRow; this.modelRow = modelRow; // Create the root element and add it to the document. AppraisalElement rootElement = new AppraisalElement(this); this.AppendChild(rootElement); // Create and populate the DataSet that represents the outline of the appraisal. This function creates a // set of linked structures that contains only the sectors, securities and positions that will appear in // this document. This driver is built from the bottom up, meaning that we start with the tax lots, // proposed orders, orders and allocations associated with the given account and build the driver up to // the topmost security classification scheme. The alternative -- starting with the classification scheme // and building down until we join with the tax lots, etc, -- turned out to be six times slower. this.appraisal = new Common.Appraisal(accountRow, modelRow, true); // This sector is a catch-all heading for securities not mapped to the given hierarchy. If everything is // mapped, then this sector won't appear in the document. SectorElement unclassifiedSector = null; // Now that the driver is built, we can begin constructing the document. The first section is the // 'Unclassified' sector. This section catches all securities that aren't explicitly mapped to the // hierarchy. This is important because classification schemes are not guaranteed to map every security. // Without this section, those unmapped securities wouldn't appear on the appraisal and wouldn't be // included in the NAV calculation. That is very bad. Note also that we skip over the classification // scheme record during the check. We know that the security classification scheme is at the top of the // hierarchy and won't have any parents. Every other record that doesn't have a parent in the hierarchy // is 'Unclassified'. foreach (AppraisalSet.SecurityRow parentSecurity in this.appraisal.Security) { if (parentSecurity.ObjectRow.GetObjectTreeRowsByFKObjectObjectTreeChildId().Length == 0) { // If the document doesn't have an 'Unclassified' sector yet, then add the sector heading. All // secutiries that are not mapped to the given hierarchy will appear under this catch-all header. if (unclassifiedSector == null) { rootElement.InsertBySortOrder(unclassifiedSector = new SectorElement(this)); } // Attach the each of the unclassified securities to the unclassified sector heading. BuildDocument(unclassifiedSector, parentSecurity.ObjectRow); } } // The report is built recursively. The 'AppraisalSet', constructed above, represents an 'inner join' of the // hierarchy information to the active position information. We'll begin traversing the 'AppraisalSet' from // the top level security: a single node representing the classification scheme. foreach (AppraisalSet.SchemeRow schemeRow in this.appraisal.Scheme) { foreach (AppraisalSet.ObjectTreeRow objectTreeRow in schemeRow.ObjectRow.GetObjectTreeRowsByFKObjectObjectTreeParentId()) { BuildDocument(rootElement, objectTreeRow.ObjectRowByFKObjectObjectTreeChildId); } } }
/// <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)); } } } } }