/// <summary> /// Creates a proposed order record. /// </summary> /// <param name="proposedOrderRow">A proposed order record from the primary ADO database.</param> /// <returns>A ProposedOrder record based on the ADO record.</returns> internal static ProposedOrder Make(ClientMarketData.ProposedOrderRow proposedOrderRow) { // Initialize the object DataRowVersion dataRowVersion = proposedOrderRow.RowState == DataRowState.Deleted ? DataRowVersion.Original : DataRowVersion.Current; // Extract the data from the ADO record. int proposedOrderId = (int)proposedOrderRow[ClientMarketData.ProposedOrder.ProposedOrderIdColumn, dataRowVersion]; TransactionType transactionType = (TransactionType)proposedOrderRow[ClientMarketData.ProposedOrder.TransactionTypeCodeColumn, dataRowVersion]; int accountId = (int)proposedOrderRow[ClientMarketData.ProposedOrder.AccountIdColumn, dataRowVersion]; int securityId = (int)proposedOrderRow[ClientMarketData.ProposedOrder.SecurityIdColumn, dataRowVersion]; int positionTypeCode = Common.TransactionType.GetPosition((int)transactionType); Position position = Position.Make(accountId, securityId, positionTypeCode); TIF tif = (TIF)proposedOrderRow[ClientMarketData.ProposedOrder.TimeInForceCodeColumn, dataRowVersion]; PricedAt pricedAt = (PricedAt)proposedOrderRow[ClientMarketData.ProposedOrder.OrderTypeCodeColumn, dataRowVersion]; decimal quantity = (decimal)proposedOrderRow[ClientMarketData.ProposedOrder.QuantityColumn, dataRowVersion]; object price1 = proposedOrderRow[ClientMarketData.ProposedOrder.Price1Column, dataRowVersion]; object price2 = proposedOrderRow[ClientMarketData.ProposedOrder.Price2Column, dataRowVersion]; // Create a new record based on the data extracted from the ADO database. return(new ProposedOrder(proposedOrderId, position, tif, pricedAt, quantity, price1, price2)); }
/// <summary> /// Handles the primary Market Data events and passes the events along to the Langauge Primitives. /// </summary> /// <param name="sender">The object that originated the event.</param> /// <param name="proposedOrderRowChangeEvent">The record change event argument.</param> public static void ProposedOrderHandler(object sender, ClientMarketData.ProposedOrderRowChangeEvent proposedOrderRowChangeEvent) { // Extract the record from the event argument. ClientMarketData.ProposedOrderRow proposedOrderRow = proposedOrderRowChangeEvent.Row; // Translate the ADO.NET row states into a record state used by the Rules Engine. Action action = Action.Nothing; switch (proposedOrderRowChangeEvent.Action) { case DataRowAction.Add: action = Action.Add; break; case DataRowAction.Delete: action = Action.Delete; break; case DataRowAction.Change: action = Action.Change; break; case DataRowAction.Commit: return; } // Place the event into a list that will be processed when the tables are no longer locked. ProposedOrder.proposedOrderEventArgList.Add(new ProposedOrderEventArgs(action, ProposedOrder.Make(proposedOrderRow))); }
/// <summary> /// Recursively creates instructions to delete proposed order of the given position. /// </summary> /// <param name="remoteBatch">The object type containing the method to delete the order relationship.</param> /// <param name="remoteTransaction">Groups several commands into a unit for execution.</param> /// <param name="accountRow">An account record, used to select proposed order records.</param> private static void Delete(RemoteBatch remoteBatch, RemoteTransaction remoteTransaction, ClientMarketData.AccountRow accountRow, ClientMarketData.SecurityRow securityRow, int positionTypeCode) { // Run through each of the proposed orders in this account and create a record to have them deleted. object[] key = new object[] { accountRow.AccountId, securityRow.SecurityId, positionTypeCode }; foreach (DataRowView dataRowView in MarketData.ProposedOrder.UKProposedOrderAccountIdSecurityIdPositionTypeCode.FindRows(key)) { // This is used to reference the current proposed order that matches the position criteria. ClientMarketData.ProposedOrderRow proposedOrderRow = (ClientMarketData.ProposedOrderRow)dataRowView.Row; // Child proposed orders aren't deleted directly, they can only be deleted when the parent is deleted. The best // example of this is cash. An account can have both child cash (related to an equity trade) or parent cash (cash // added directly to the account with no offsetting trade). If a reqest is made to delete cash, only the parent // cash should be deleted. The account will appear to have a cash balance until the equity attached to the child // cash is deleted. if (!Relationship.IsChildProposedOrder(proposedOrderRow)) { Delete(remoteBatch, remoteTransaction, proposedOrderRow); } } }
/// <summary> /// Creates a batch command to delete a proposed order and it's links. /// </summary> /// <param name="remoteBatch"></param> /// <param name="remoteTransaction"></param> /// <param name="parentProposedOrder"></param> public static void Delete(RemoteBatch remoteBatch, RemoteTransaction remoteTransaction, ClientMarketData.ProposedOrderRow parentProposedOrder) { // These define the assembly and the types within those assemblies that will be used to create the proposed orders on // the middle tier. RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Core"); RemoteType proposedOrderType = remoteAssembly.Types.Add("Shadows.WebService.Core.ProposedOrder"); RemoteType proposedOrderTreeType = remoteAssembly.Types.Add("Shadows.WebService.Core.ProposedOrderTree"); // Proposed orders have a hierarchy. For example, orders for equities will be linked to foreach (ClientMarketData.ProposedOrderTreeRow proposedOrderTree in parentProposedOrder.GetProposedOrderTreeRowsByFKProposedOrderProposedOrderTreeParentId()) { // Create a command to delete the relationship between the parent and child. RemoteMethod deleteRelation = proposedOrderTreeType.Methods.Add("Delete"); deleteRelation.Transaction = remoteTransaction; deleteRelation.Parameters.Add("rowVersion", proposedOrderTree.RowVersion); deleteRelation.Parameters.Add("parentId", proposedOrderTree.ParentId); deleteRelation.Parameters.Add("childId", proposedOrderTree.ChildId); // This relatioship will give us access to the child proposed order. ClientMarketData.ProposedOrderRow childProposedOrder = proposedOrderTree.ProposedOrderRowByFKProposedOrderProposedOrderTreeChildId; // Create a command to delete the child proposed order. RemoteMethod deleteChild = proposedOrderType.Methods.Add("Delete"); deleteChild.Transaction = remoteTransaction; deleteChild.Parameters.Add("rowVersion", childProposedOrder.RowVersion); deleteChild.Parameters.Add("proposedOrderId", childProposedOrder.ProposedOrderId); } // Create a command to delete the parent proposed order. RemoteMethod deleteParent = proposedOrderType.Methods.Add("Delete"); deleteParent.Transaction = remoteTransaction; deleteParent.Parameters.Add("rowVersion", parentProposedOrder.RowVersion); deleteParent.Parameters.Add("proposedOrderId", parentProposedOrder.ProposedOrderId); }
/// <summary> /// Creates an element in the Appraisal Document that represents a fund's or account's position. /// </summary> /// <param name="appraisalDocument">The parent document.</param> /// <param name="driverAccount">Identifies the individual position at the account/security/position level.</param> public AccountElement(AppraisalDocument appraisalDocument, AppraisalSet.AccountRow driverAccount) : base("Account", appraisalDocument) { // Get the account record from the account id. This record drives most of the data that appears in this element. ClientMarketData.AccountRow accountRow = ClientMarketData.Account.FindByAccountId(driverAccount.AccountId); // Count up the compliance violations int violationCount = 0; foreach (DataRowView dataRowView in ClientMarketData.Violation.UKViolationAccountIdSecurityIdPositionTypeCode.FindRows( new object[] { driverAccount.AccountId, driverAccount.SecurityId, driverAccount.PositionTypeCode })) { ClientMarketData.ViolationRow violationRow = (ClientMarketData.ViolationRow)dataRowView.Row; if (violationRow.RestrictionRow.Severity > 0) { violationCount++; } } AddAttribute("Violation", violationCount); // Add the essential attributes to the element. AddAttribute("AccountId", accountRow.AccountId.ToString()); // Aggregate the tax lot positions and cost. decimal taxLotQuantity = 0.0M; decimal taxLotCost = 0.0M; foreach (ClientMarketData.TaxLotRow taxLotRow in accountRow.GetTaxLotRows()) { if (taxLotRow.SecurityId == driverAccount.SecurityId && taxLotRow.PositionTypeCode == driverAccount.PositionTypeCode) { taxLotQuantity += taxLotRow.Quantity; taxLotCost += taxLotRow.Cost * taxLotRow.Quantity; } } AddAttribute("TaxLotQuantity", taxLotQuantity.ToString()); AddAttribute("TaxLotCost", taxLotCost.ToString()); // Aggregate the proposed orders positions. decimal proposedOrderQuantity = 0.0M; foreach (DataRowView dataRowView in appraisalDocument.proposedOrderView.FindRows(new object[] { driverAccount.AccountId, driverAccount.SecurityId, driverAccount.PositionTypeCode })) { ClientMarketData.ProposedOrderRow proposedOrderRow = (ClientMarketData.ProposedOrderRow)dataRowView.Row; proposedOrderQuantity += proposedOrderRow.Quantity * proposedOrderRow.TransactionTypeRow.QuantitySign; } AddAttribute("ProposedOrderQuantity", proposedOrderQuantity.ToString()); // Aggregate the orders. decimal orderQuantity = 0.0M; foreach (DataRowView dataRowView in appraisalDocument.orderView.FindRows(new object[] { driverAccount.AccountId, driverAccount.SecurityId, driverAccount.PositionTypeCode })) { ClientMarketData.OrderRow orderRow = (ClientMarketData.OrderRow)dataRowView.Row; orderQuantity += orderRow.Quantity * orderRow.TransactionTypeRow.QuantitySign; } AddAttribute("OrderQuantity", orderQuantity.ToString()); // Aggregate the allocations. decimal allocationQuantity = 0.0M; foreach (DataRowView dataRowView in appraisalDocument.allocationView.FindRows(new object[] { driverAccount.AccountId, driverAccount.SecurityId, driverAccount.PositionTypeCode })) { ClientMarketData.AllocationRow allocationRow = (ClientMarketData.AllocationRow)dataRowView.Row; allocationQuantity += allocationRow.Quantity * allocationRow.TransactionTypeRow.QuantitySign; } AddAttribute("AllocationQuantity", allocationQuantity.ToString()); }
/// <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); } } }
private static void Update(RemoteBatch remoteBatch, RemoteTransaction remoteTransaction, ClientMarketData.ProposedOrderRow parentProposedOrder, decimal quantityInstruction) { // These define the assembly and the types within those assemblies that will be used to create the proposed orders on // the middle tier. RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Core"); RemoteType proposedOrderType = remoteAssembly.Types.Add("Shadows.WebService.Core.ProposedOrder"); ClientMarketData.AccountRow accountRow = parentProposedOrder.AccountRow; ClientMarketData.SecurityRow securityRow = parentProposedOrder.SecurityRowByFKSecurityProposedOrderSecurityId; // This will turn the signed quantity into an absolute quantity and a transaction code (e.g. -1000 is turned into a // SELL of 1000 shares). decimal parentQuantity = Math.Abs(quantityInstruction); int parentTransactionTypeCode = TransactionType.Calculate(securityRow.SecurityTypeCode, parentProposedOrder.PositionTypeCode, quantityInstruction); // The time in force first comes from the user preferences, next, account settings and finally defaults to a day // orders. int timeInForceCode = !ClientPreferences.IsTimeInForceCodeNull() ? ClientPreferences.TimeInForceCode : !accountRow.IsTimeInForceCodeNull() ? accountRow.TimeInForceCode : TimeInForce.DAY; // The destination blotter comes first from the user preferences, second from the account preferences, and finally uses // the auto-routing logic. int blotterId = !ClientPreferences.IsBlotterIdNull() ? ClientPreferences.BlotterId : !accountRow.IsBlotterIdNull() ? accountRow.BlotterId : TradingSupport.AutoRoute(securityRow, parentQuantity); // Create a command to update the proposed order. RemoteMethod updateParent = proposedOrderType.Methods.Add("Update"); updateParent.Transaction = remoteTransaction; updateParent.Parameters.Add("rowVersion", parentProposedOrder.RowVersion); updateParent.Parameters.Add("proposedOrderId", parentProposedOrder.ProposedOrderId); updateParent.Parameters.Add("accountId", parentProposedOrder.AccountId); updateParent.Parameters.Add("securityId", parentProposedOrder.SecurityId); updateParent.Parameters.Add("settlementId", parentProposedOrder.SettlementId); updateParent.Parameters.Add("blotterId", blotterId); updateParent.Parameters.Add("positionTypeCode", parentProposedOrder.PositionTypeCode); updateParent.Parameters.Add("transactionTypeCode", parentTransactionTypeCode); updateParent.Parameters.Add("timeInForceCode", timeInForceCode); updateParent.Parameters.Add("orderTypeCode", OrderType.Market); updateParent.Parameters.Add("quantity", parentQuantity); foreach (ClientMarketData.ProposedOrderTreeRow proposedOrderTree in parentProposedOrder.GetProposedOrderTreeRowsByFKProposedOrderProposedOrderTreeParentId()) { ClientMarketData.ProposedOrderRow childProposedOrder = proposedOrderTree.ProposedOrderRowByFKProposedOrderProposedOrderTreeChildId; // If this is the settlement part of the order, then adjust the quantity. if (childProposedOrder.SecurityId == parentProposedOrder.SettlementId) { // The settlement security is needed for the calculation of the cash impact of this trade. ClientMarketData.CurrencyRow currencyRow = MarketData.Currency.FindByCurrencyId(childProposedOrder.SettlementId); decimal marketValue = parentQuantity * securityRow.QuantityFactor * Price.Security(currencyRow, securityRow) * securityRow.PriceFactor * TransactionType.GetCashSign(parentTransactionTypeCode); decimal childQuantity = Math.Abs(marketValue); int childTransactionTypeCode = TransactionType.Calculate(securityRow.SecurityTypeCode, parentProposedOrder.PositionTypeCode, marketValue); // Create a command to update the proposed order. RemoteMethod updateChild = proposedOrderType.Methods.Add("Update"); updateChild.Transaction = remoteTransaction; updateChild.Parameters.Add("rowVersion", childProposedOrder.RowVersion); updateChild.Parameters.Add("proposedOrderId", childProposedOrder.ProposedOrderId); updateChild.Parameters.Add("accountId", childProposedOrder.AccountId); updateChild.Parameters.Add("securityId", childProposedOrder.SecurityId); updateChild.Parameters.Add("settlementId", childProposedOrder.SettlementId); updateChild.Parameters.Add("blotterId", blotterId); updateChild.Parameters.Add("positionTypeCode", parentProposedOrder.PositionTypeCode); updateChild.Parameters.Add("transactionTypeCode", childTransactionTypeCode); updateChild.Parameters.Add("timeInForceCode", timeInForceCode); updateChild.Parameters.Add("orderTypeCode", OrderType.Market); updateChild.Parameters.Add("quantity", childQuantity); } } }