/// <summary> /// Creates a temporary model based on the current sector level targets. /// </summary> /// <param name="accountRow">An account used as a basis for the targets.</param> /// <param name="schemeRow">The scheme used to select sector targets.</param> /// <returns>A batch of commands that will create a model containing the current sector weights of the account.</returns> private static ModelBatch CreateSectorSelfModel(ClientMarketData.AccountRow accountRow, ClientMarketData.SchemeRow schemeRow) { // This command batch will create a temporary model and populate it with the current position level percentages as the // target values. ModelBatch modelBatch = new ModelBatch(); RemoteTransaction remoteTransaction = modelBatch.Transactions.Add(); RemoteAssembly remoteAssembly = modelBatch.Assemblies.Add("Service.Core"); RemoteType remoteType = remoteAssembly.Types.Add("Shadows.WebService.Core.Model"); // Create the temporary model. RemoteMethod insertModel = remoteType.Methods.Add("Insert"); insertModel.Parameters.Add("modelId", DataType.Int, Direction.ReturnValue); insertModel.Parameters.Add("rowVersion", DataType.Long, Direction.Output); insertModel.Parameters.Add("modelTypeCode", ModelType.Sector); insertModel.Parameters.Add("name", "Untitled"); insertModel.Parameters.Add("schemeId", schemeRow.SchemeId); insertModel.Parameters.Add("algorithmId", Algorithm.SectorMergeRebalancer); insertModel.Parameters.Add("temporary", true); // The 'Self Sector' uses the market value of all the account and sub-account. decimal accountMarketValue = MarketValue.Calculate(accountRow.CurrencyRow, accountRow, MarketValueFlags.EntirePosition | MarketValueFlags.IncludeChildAccounts); // No need to construct a model if the account market value is zero. if (accountMarketValue != 0.0M) { // Create a new outline for the model to follow. This will collect the tax lots, proposed orders, orders // and allocations into industry classification sectors. Common.Appraisal appraisal = new Common.Appraisal(accountRow, schemeRow, true); // The object Type for this operation. RemoteType sectorTargetType = remoteAssembly.Types.Add("Shadows.WebService.Core.SectorTarget"); // Now that we have an outline to follow, we are going to run through each of the sectors, calculate the market // value, and create an entry in the temporary model for that sector and it's current weight of the overall market // value. foreach (AppraisalSet.SchemeRow driverScheme in appraisal.Scheme) { foreach (AppraisalSet.ObjectTreeRow driverTree in driverScheme.ObjectRow.GetObjectTreeRowsByFKObjectObjectTreeParentId()) { foreach (AppraisalSet.SectorRow driverSector in driverTree.ObjectRowByFKObjectObjectTreeChildId.GetSectorRows()) { // This sector is the destination for the market value calculation. ClientMarketData.SectorRow sectorRow = ClientMarketData.Sector.FindBySectorId(driverSector.SectorId); // Calculate the market value of all the securities held by all the accounts in the current sector. decimal sectorMarketValue = MarketValue.Calculate(accountRow.CurrencyRow, accountRow, sectorRow, MarketValueFlags.EntirePosition | MarketValueFlags.IncludeChildAccounts); // Add the position level target to the model. RemoteMethod insertSector = sectorTargetType.Methods.Add("Insert"); insertSector.Parameters.Add("modelId", insertModel.Parameters["modelId"]); insertSector.Parameters.Add("sectorId", sectorRow.SectorId); insertSector.Parameters.Add("percent", sectorMarketValue / accountMarketValue); } } } } // Save the reference to the 'modelId' return parameter. modelBatch.ModelIdParameter = insertModel.Parameters["modelId"]; // This batch will create a temporary model based on the sector totals of the original account. return(modelBatch); }
/// <summary> /// Creates a temporary model based on the current position level targets. /// </summary> /// <param name="accountRow">An account used as a basis for the targets.</param> /// <param name="schemeRow">The scheme used to select sector targets.</param> /// <returns>A batch of commands that will create a model containing the current position weights of the account.</returns> private static ModelBatch CreatePositionSelfModel(ClientMarketData.AccountRow accountRow, ClientMarketData.SchemeRow schemeRow) { // Create the batch and fill it in with the assembly and type needed for this function. ModelBatch modelBatch = new ModelBatch(); RemoteTransaction remoteTransaction = modelBatch.Transactions.Add(); RemoteAssembly remoteAssembly = modelBatch.Assemblies.Add("Service.Core"); RemoteType remoteType = remoteAssembly.Types.Add("Shadows.WebService.Core.Model"); // Create the temporary, position model based on the scheme used by the original account. RemoteMethod insertModel = remoteType.Methods.Add("Insert"); insertModel.Parameters.Add("modelId", DataType.Int, Direction.ReturnValue); insertModel.Parameters.Add("rowVersion", DataType.Long, Direction.Output); insertModel.Parameters.Add("modelTypeCode", ModelType.Security); insertModel.Parameters.Add("name", "Untitled"); insertModel.Parameters.Add("schemeId", schemeRow.SchemeId); insertModel.Parameters.Add("algorithmId", Algorithm.SecurityRebalancer); insertModel.Parameters.Add("temporary", true); // The 'Self Security' model uses the market value of all the positions, regardless of account or sub-account, when // calculating the denominator for the percentages. decimal accountMarketValue = MarketValue.Calculate(accountRow.CurrencyRow, accountRow, MarketValueFlags.EntirePosition | MarketValueFlags.IncludeChildAccounts); // If the account market value is zero, we can't do much more to create a model. if (accountMarketValue != 0.0M) { // Create a new outline for the model to follow. This will collect the tax lots, proposed orders orders and // allocations into positions that can be used for calculating percentages. Common.Appraisal appraisal = new Common.Appraisal(accountRow, true); // Run through each of the positions, starting with the security. foreach (AppraisalSet.SecurityRow driverSecurity in appraisal.Security) { // This is a position is the destination for the market value calculation. ClientMarketData.SecurityRow securityRow = ClientMarketData.Security.FindBySecurityId(driverSecurity.SecurityId); // The object Type for this operation. RemoteType positionTargetType = remoteAssembly.Types.Add("Shadows.WebService.Core.PositionTarget"); // Run through each of the positions in the appraisal calculating the market value of each position. The ratio // of this market value to the account's market value is the model percentage. foreach (AppraisalSet.PositionRow positionRow in driverSecurity.GetPositionRows()) { // Calculate the market value of the given position. decimal securityMarketValue = MarketValue.Calculate(accountRow.CurrencyRow, accountRow, securityRow, positionRow.PositionTypeCode, MarketValueFlags.EntirePosition | MarketValueFlags.EntirePosition); // Add the position level target to the model. RemoteMethod insertPosition = positionTargetType.Methods.Add("Insert"); insertPosition.Parameters.Add("modelId", insertModel.Parameters["modelId"]); insertPosition.Parameters.Add("securityId", securityRow.SecurityId); insertPosition.Parameters.Add("positionTypeCode", positionRow.PositionTypeCode); insertPosition.Parameters.Add("percent", securityMarketValue / accountMarketValue); } } } // Save the reference to the 'modelId' return parameter. modelBatch.ModelIdParameter = insertModel.Parameters["modelId"]; // This batch will create a temporary model based on the position totals of the original account. return(modelBatch); }
/// <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); } } }