Beispiel #1
0
        /// <summary>
        /// Execute the remote batch and catch any batch errors.
        /// </summary>
        /// <param name="remoteBatch"></param>
        public static void Send(RemoteBatch remoteBatch)
        {
            // The top level window of the application is needed as the owner of the error message dialog box that will pop up to
            // process the errors.
            System.Windows.Forms.Control activeForm      = Form.ActiveForm;
            System.Windows.Forms.Control topLevelControl = activeForm == null ? null : activeForm.TopLevelControl;

            try
            {
                // Execute the remote batch.
                Execute(remoteBatch);
            }
            catch (BatchException batchException)
            {
                // Display each error from the batch until the user hits the 'Cancel' button, or until they are all displayed.
                foreach (RemoteException remoteException in batchException.Exceptions)
                {
                    DialogResult dialogResult = MessageBox.Show(topLevelControl, remoteException.Message, "Quasar Error",
                                                                MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
                    if (dialogResult == DialogResult.Cancel)
                    {
                        break;
                    }
                }
            }
            catch (Exception exception)
            {
                // Write the error and stack trace out to the debug listener
                Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));
            }
        }
Beispiel #2
0
        /// <summary>
        /// Sends a batch of commands to the server and processes the results.
        /// </summary>
        private static void SendBatch()
        {
            // Create a new web client that will serve as the connection point to the server.
            WebClient webClient = new WebClient();

            webClient.Timeout = TableLoader.timeout;

            // Call the web services to execute the command batch.
            remoteBatch.Merge(webClient.Execute(remoteBatch));

            // Any error during the batch will terminate the execution of the remaining records in the data file.
            if (remoteBatch.HasExceptions)
            {
                // Display each error on the console.
                foreach (RemoteException remoteException in remoteBatch.Exceptions)
                {
                    Console.WriteLine(remoteException.Message);
                }

                // This will signal the error exit from this loader.
                hasErrors = true;
            }

            // Clearing out the batch indicates that a new header should be created for the next set of commands.
            remoteBatch       = null;
            remoteTransaction = null;
            remoteAssembly    = null;
            remoteType        = null;
        }
Beispiel #3
0
        /// <summary>
        /// Load and execute a command batch.
        /// </summary>
        /// <param name="rootNode">The root node of the Xml Data structure that contains the command.</param>
        private static void LoadCommand(XmlNode rootNode)
        {
            // Read each of the transactions and send them to the server.
            foreach (XmlNode transactionNode in rootNode.SelectNodes("transaction"))
            {
                // Ignore Comment Nodes.
                if (transactionNode.NodeType == XmlNodeType.Comment)
                {
                    continue;
                }

                // Each transaction in the batch is handled as a unit.  That is, everything between the start and end <Transaction>
                // tags will be executed or rolled back as a unit.
                remoteBatch       = new RemoteBatch();
                remoteTransaction = remoteBatch.Transactions.Add();
                remoteAssembly    = null;
                remoteType        = null;

                // The <Assembly> tag specifies the name of an assembly where the object and methods are found.
                foreach (XmlNode assemblyNode in transactionNode.SelectNodes("assembly"))
                {
                    LoadAssembly(assemblyNode, 0);
                }

                // Once the entire transaction has been loaded, send it off to the server.
                SendBatch();
            }

            // If the batch file doesn't contain explicit transactions, then implicit ones are assumed and the processing of the file
            // continues with the 'assembly' nodes.
            XmlNodeList assemblyNodes = rootNode.SelectNodes("assembly");

            if (assemblyNodes.Count != 0)
            {
                // This will tell the 'LoadAssembly' to determine the size of the batch from the number of records processed.
                remoteBatch       = null;
                remoteTransaction = null;
                remoteAssembly    = null;
                remoteType        = null;

                // If an assembly is included outside of a Transaction, then the transaction is implicit and the size of the
                // transaction is the 'batchSize' parameter.
                foreach (XmlNode assemblyNode in assemblyNodes)
                {
                    // Load the assebly node ninto the batch.
                    LoadAssembly(assemblyNode, batchSize);

                    // There will be records in the batch when the above method returns (unless there are exactly as many records
                    // in the batch as the batch size).  This will send the remaining records to the server.
                    if (remoteBatch != null)
                    {
                        SendBatch();
                    }
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Returns a set of orders that will achieve the targets specified by the model.
        /// </summary>
        /// <param name="accountRow">The account or parent account to be rebalanced.</param>
        /// <param name="modelRow">The target percentages to use for rebalancing.</param>
        /// <returns>A Dataset of new, updated and deleted orders.</returns>
        public static RemoteBatch Rebalance(ClientMarketData.AccountRow accountRow, ClientMarketData.ModelRow modelRow)
        {
            // The orders to insert, update and delete orders to achieve the target percentages will be put in this DataSet.
            RemoteBatch       remoteBatch       = new RemoteBatch();
            RemoteTransaction remoteTransaction = remoteBatch.Transactions.Add();

            // Rebalance the parent account and all it's children.
            SelectedSecurity.RecurseAccounts(remoteBatch, remoteTransaction, accountRow, modelRow);

            // This is the sucessful result of rebalancing.
            return(remoteBatch);
        }
Beispiel #5
0
		/// <summary>
		/// Creates a block order.
		/// </summary>
		/// <param name="configurationId">Defines which external fields are used to identify an object.</param>
		/// <param name="blotterId">The destination blotter for the trade.</param>
		/// <param name="securityId">The security.</param>
		/// <param name="transactionType">The type of transaction.</param>
		public BlockOrder(Blotter blotter, Security security, TransactionType transactionType)
		{

			// Create a block order on the server.
			RemoteBatch remoteBatch = new RemoteBatch();
			RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Trading");
			RemoteType remoteType = remoteAssembly.Types.Add("Shadows.WebService.Trading.BlockOrder");
			RemoteMethod remoteMethod = remoteType.Methods.Add("Insert");
			remoteMethod.Parameters.Add("blockOrderId", DataType.Int, Direction.ReturnValue);
			remoteMethod.Parameters.Add("blotterId", blotter.BlotterId);
			remoteMethod.Parameters.Add("securityId", security.SecurityId);
			remoteMethod.Parameters.Add("settlementId", security.SettlementId);
			remoteMethod.Parameters.Add("transactionTypeCode", (int)transactionType);
			ClientMarketData.Execute(remoteBatch);

			// Now that the block order is created, construct the in-memory version of the record.
			int blockOrderId = (int)remoteMethod.Parameters["blockOrderId"].Value;

			try
			{

				// Lock the tables.
				Debug.Assert(!ClientMarketData.AreLocksHeld);
				ClientMarketData.BlockOrderLock.AcquireReaderLock(CommonTimeout.LockWait);
				ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);
				ClientMarketData.SecurityLock.AcquireReaderLock(CommonTimeout.LockWait);

				ClientMarketData.BlockOrderRow blockOrderRow = ClientMarketData.BlockOrder.FindByBlockOrderId(blockOrderId);
				if (blockOrderRow == null)
					throw new Exception(String.Format("BlockOrder {0} doesn't exist", blockOrderId));

				this.blockOrderId = blockOrderRow.BlockOrderId;
				this.security = Security.Make(blockOrderRow.SecurityRowByFKSecurityBlockOrderSecurityId.SecurityId);
				this.settlement = Security.Make(blockOrderRow.SecurityRowByFKSecurityBlockOrderSettlementId.SecurityId);
				this.transactionType = (TransactionType)blockOrderRow.TransactionTypeCode;

			}
			finally
			{

				// Release the table locks.
				if (ClientMarketData.BlockOrderLock.IsReaderLockHeld) ClientMarketData.BlockOrderLock.ReleaseReaderLock();
				if (ClientMarketData.ObjectLock.IsReaderLockHeld) ClientMarketData.ObjectLock.ReleaseReaderLock();
				if (ClientMarketData.SecurityLock.IsReaderLockHeld) ClientMarketData.SecurityLock.ReleaseReaderLock();
				Debug.Assert(!ClientMarketData.AreLocksHeld);

			}

		}
Beispiel #6
0
        public static void Flush()
        {
            if (CommandBatch.remoteBatch.RemoteMethod.Rows.Count > 0)
            {
                RemoteBatch currentBatch = null;

                lock (typeof(CommandBatch))
                {
                    currentBatch             = CommandBatch.remoteBatch;
                    CommandBatch.remoteBatch = new RemoteBatch();
                }

                new WorkerThread(new ThreadHandler(FlushThread), "Command Batch Execution", currentBatch);
            }
        }
Beispiel #7
0
		/// <summary>
		/// Executes a block order.
		/// </summary>
		/// <param name="configurationId">Defines which external fields are used to identify an object.</param>
		/// <param name="brokerId">The destination broker for the order.</param>
		/// <param name="tif">Specifies a time limit on the order.</param>
		/// <param name="quantity">The number of units to be traded.</param>
		/// <param name="pricedAt">Specifies how the order is to be priced.</param>
		/// <param name="limitPrice">A limit price for the order.</param>
		public void Execute(Broker broker, TIF tif, decimal quantity, PricedAt pricedAt, decimal limitPrice)
		{

			RemoteBatch remoteBatch = new RemoteBatch();
			RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Trading");
			RemoteType remoteType = remoteAssembly.Types.Add("Shadows.WebService.Trading.BlockOrder");
			RemoteMethod remoteMethod = remoteType.Methods.Add("Execute");
			remoteMethod.Parameters.Add("blockOrderId", this.blockOrderId);
			remoteMethod.Parameters.Add("brokerId", broker.BrokerId);
			remoteMethod.Parameters.Add("timeInForceCode", (int)tif);
			remoteMethod.Parameters.Add("quantity", quantity);
			remoteMethod.Parameters.Add("orderTypeCode", (int)pricedAt);
			remoteMethod.Parameters.Add("price1", limitPrice);
			ClientMarketData.Execute(remoteBatch);

		}
Beispiel #8
0
        public Restriction(string restrictionId, Severity severity, Approval approval, string description)
        {
            RemoteBatch    remoteBatch    = new RemoteBatch();
            RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Core");
            RemoteType     remoteType     = remoteAssembly.Types.Add("Shadows.WebService.Core.Restriction");

            RemoteMethod remoteMethod = remoteType.Methods.Add("Insert");

            remoteMethod.Parameters.Add("internalRestrictionId", DataType.Int, Direction.ReturnValue);
            remoteMethod.Parameters.Add("severity", (int)severity);
            remoteMethod.Parameters.Add("approval", (int)approval);
            remoteMethod.Parameters.Add("description", description);
            remoteMethod.Parameters.Add("userId0", restrictionId);
            ClientMarketData.Send(remoteBatch);

            Initialize((int)remoteMethod.Parameters["internalRestrictionId"].Value);
        }
Beispiel #9
0
        /// <summary>
        /// Returns a set of orders that will achieve the targets specified by the model.
        /// </summary>
        /// <param name="accountRow">The account or parent account to be rebalanced.</param>
        /// <param name="modelRow">The target percentages to use for rebalancing.</param>
        /// <returns>A Dataset of new, updated and deleted orders.</returns>
        public static RemoteBatch Rebalance(ClientMarketData.AccountRow accountRow, ClientMarketData.ModelRow modelRow)
        {
            // The orders to insert, update and delete orders to achieve the target percentages will be put in this
            // DataSet.
            RemoteBatch       remoteBatch       = new RemoteBatch();
            RemoteTransaction remoteTransaction = remoteBatch.Transactions.Add();

            // The outline of the appraisal will be needed to make calculations based on a position, that is a security,
            // account, position type combination.  Note that we're also including all the model securities in the
            // outline.  This triggers a rebalance if a security exists in the model, but doesn't exist yet in the
            // appraisal.
            AppraisalSet appraisalSet = new Appraisal(accountRow, modelRow, true);

            // Rebalance the parent account and all it's children.
            Security.RecurseAccounts(remoteBatch, remoteTransaction, appraisalSet, accountRow, modelRow);

            // This is the sucessful result of rebalancing.
            return(remoteBatch);
        }
Beispiel #10
0
        /// <summary>
        /// Returns a set of orders that will achieve the targets specified by the model.
        /// </summary>
        /// <param name="accountRow">The account or parent account to be rebalanced.</param>
        /// <param name="modelRow">The target percentages to use for rebalancing.</param>
        /// <returns>A Dataset of new, updated and deleted orders.</returns>
        public static RemoteBatch Rebalance(ClientMarketData.AccountRow accountRow, ClientMarketData.ModelRow modelRow)
        {
            // Make sure the scheme still exists in the in-memory database.  We need it to rebalance the appraisal.
            ClientMarketData.SchemeRow schemeRow;
            if ((schemeRow = ClientMarketData.Scheme.FindBySchemeId(modelRow.SchemeId)) == null)
            {
                throw new ArgumentException("Scheme doesn't exist in the ClientMarketData", modelRow.SchemeId.ToString());
            }

            // The final result of this method is a command batch that can be sent to the server.
            RemoteBatch       remoteBatch       = new RemoteBatch();
            RemoteTransaction remoteTransaction = remoteBatch.Transactions.Add();

            // Rebalance the parent account and all it's children.
            RecurseAccounts(remoteBatch, remoteTransaction, accountRow, modelRow, schemeRow);

            // The sucessful result of rebalancing.
            return(remoteBatch);
        }
Beispiel #11
0
		/// <summary>
		/// Adds an order to a block order.
		/// </summary>
		/// <param name="configurationId">Defines which external fields are used to identify an object.</param>
		/// <param name="accountId">The destination account for the order.</param>
		/// <param name="tif">Specifies a time limit on the order.</param>
		/// <param name="quantity">The number of units to be traded.</param>
		/// <returns>An internal identifier used to track the order.</returns>
		public int AddOrder(Account account, TIF tif, decimal quantity)
		{

			RemoteBatch remoteBatch = new RemoteBatch();
			RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Trading");
			RemoteType remoteType = remoteAssembly.Types.Add("Shadows.WebService.Trading.Order");
			RemoteMethod remoteMethod = remoteType.Methods.Add("Insert");
			remoteMethod.Parameters.Add("orderId", DataType.Int, Direction.ReturnValue);
			remoteMethod.Parameters.Add("blockOrderId", this.blockOrderId);
			remoteMethod.Parameters.Add("accountId", account.AccountId);
			remoteMethod.Parameters.Add("securityId", this.Security.SecurityId);
			remoteMethod.Parameters.Add("settlementId", this.Settlement.SecurityId);
			remoteMethod.Parameters.Add("timeInForceCode", (int)tif);
			remoteMethod.Parameters.Add("transactionTypeCode", (int)this.transactionType);
			remoteMethod.Parameters.Add("orderTypeCode", (int)PricedAt.Market);
			remoteMethod.Parameters.Add("quantity", quantity);
			ClientMarketData.Execute(remoteBatch);

			return (int)remoteMethod.Parameters["orderId"].Value;

		}
Beispiel #12
0
        /// <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);
                }
            }
        }
Beispiel #13
0
        /// <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);
        }
Beispiel #14
0
        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);
                }
            }
        }
Beispiel #15
0
        /// <summary>
        /// Load up an assembly section of a batch.
        /// </summary>
        /// <param name="assemblyNode"></param>
        private static void LoadAssembly(XmlNode assemblyNode, int batchSize)
        {
            // Ignore Comment Nodes.
            if (assemblyNode.NodeType == XmlNodeType.Comment)
            {
                return;
            }

            // Add an Assembly specifier to the batch.  This essentially describes the DLL where the methods are found.
            string assemblyName = assemblyNode.Attributes["name"].Value;

            // Each assembly can have one or more Objects (or Types) which can be instantiated.  The batch command
            // processing can call static methods belonging to the instantiated object.
            foreach (XmlNode typeNode in assemblyNode.SelectNodes("type"))
            {
                // Ignore Comment Nodes.
                if (typeNode.NodeType == XmlNodeType.Comment)
                {
                    continue;
                }

                // Loading the database involves creating a batch of commands and sending them off as a transaction.
                // This gives the server a chance to pipeline a large chunk of processing, without completely locking
                // up the server for the entire set of data.  This will construct a header for the command batch which
                // gives information about which assembly contains the class that is used to load the data.
                string typeName = typeNode.Attributes["name"].Value;

                // Attach each method and it's parameters to the command batch.
                foreach (XmlNode methodNode in typeNode.SelectNodes("method"))
                {
                    // Ignore Comment Nodes.
                    if (methodNode.NodeType == XmlNodeType.Comment)
                    {
                        continue;
                    }

                    // The 'remoteBatch' will be cleared after it is sent to the server.  Make sure a batch exists before adding
                    // methods and parameters to it.
                    if (remoteBatch == null)
                    {
                        // Loading the database involves creating a batch of commands and sending them off as a transaction.  This
                        // gives the server a chance to pipeline a large chunk of processing, without completely locking up the
                        // server for the entire set of data.  This will create a batch for the next bunch of commands.
                        remoteBatch       = new RemoteBatch();
                        remoteTransaction = remoteBatch.Transactions.Add();

                        // This counts the number of records placed in the batch.
                        batchCounter = 0;
                    }

                    if (remoteAssembly == null || remoteAssembly.Name != assemblyName)
                    {
                        remoteAssembly = remoteBatch.Assemblies.Add(assemblyName);
                    }

                    if (remoteType == null || remoteType.Name != typeName)
                    {
                        remoteType = remoteAssembly.Types.Add(typeName);
                    }

                    // Each method is part of the transaction defined by the tagged outline structure of the input
                    // file.
                    RemoteMethod remoteMethod = remoteType.Methods.Add(methodNode.Attributes["name"].Value);
                    remoteMethod.Transaction = remoteTransaction;

                    // Load each of the parameters into the method structure.
                    foreach (XmlNode parameterNode in methodNode.ChildNodes)
                    {
                        // Ignore Comment Nodes.
                        if (parameterNode.NodeType == XmlNodeType.Comment)
                        {
                            continue;
                        }

                        // Add the next parameter to the method.
                        remoteMethod.Parameters.Add(parameterNode.Name, parameterNode.InnerText);
                    }

                    // One more record for the grand total, one more record for the number in the current batch.
                    recordCounter++;
                    batchCounter++;

                    // This will check to see if it's time to send the batch.  A batch is sent when the 'batchSize' has been
                    // reached, or if the last record has just been converted into a command.
                    if (batchSize != 0 && recordCounter % batchSize == 0)
                    {
                        SendBatch();
                    }
                }
            }
        }
Beispiel #16
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);
                }
            }
        }
Beispiel #17
0
        static int Main(string[] args)
        {
            // If this flag is set during the processing of the file, the program will exit with an error code.
            bool hasErrors = false;

            try
            {
                // Defaults
                assemblyName              = "Service.External";
                namespaceName             = "Shadows.WebService.External";
                externalConfigurationCode = "DEFAULT";
                argumentState             = ArgumentState.FileName;

                // Parse the command line for arguments.
                foreach (string argument in args)
                {
                    // Decode the current argument into a state.
                    if (argument == "-c")
                    {
                        argumentState = ArgumentState.ConfigurationCode; continue;
                    }
                    if (argument == "-i")
                    {
                        argumentState = ArgumentState.FileName; continue;
                    }
                    if (argument == "-id")
                    {
                        argumentState = ArgumentState.StylesheetId; continue;
                    }
                    if (argument == "-t")
                    {
                        argumentState = ArgumentState.StylesheetTypeCode; continue;
                    }

                    // The parsing state will determine which variable is read next.
                    switch (argumentState)
                    {
                    // Read the command line argument into the proper variable based on the parsing state.
                    case ArgumentState.ConfigurationCode: externalConfigurationCode = argument; break;

                    case ArgumentState.StylesheetTypeCode: stylesheetTypeCode = argument; break;

                    case ArgumentState.FileName: fileName = argument; break;

                    case ArgumentState.Name: name = argument; break;

                    case ArgumentState.StylesheetId: StylesheetId = argument; break;
                    }

                    // The default state for the parser is to look for a file name.
                    argumentState = ArgumentState.FileName;
                }

                // If no file name was specified, we return an error.
                if (fileName == null)
                {
                    throw new Exception("Usage: Loader.Stylesheet -i <FileName>");
                }

                // Load up an XML document with the contents of the file specified on the command line.
                XmlDocument stylesheet = new XmlDocument();
                stylesheet.Load(fileName);

                // The XML document has several nodes that need to be read -- and then removed -- that contain attributes of the
                // stylesheet.  These nodes can be found easily using the XSL Path functions which need a namespace manager to sort
                // out the tag prefixes.
                XmlNamespaceManager namespaceManager = new XmlNamespaceManager(stylesheet.NameTable);
                namespaceManager.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform");
                namespaceManager.AddNamespace("sss", "urn:schemas-shadows-com:shadows:stylesheet");

                // The spreadhseet source has several nodes which contain information about how the data in the XML document should
                // be loaded into the server, such as the stylesheet identifier, the name and the stylesheet style.  They are found
                // at this node.  After these information nodes have been read, they are removed from the stylesheet source.
                XmlNode stylesheetNode = stylesheet.SelectSingleNode("xsl:stylesheet", namespaceManager);
                if (stylesheetNode == null)
                {
                    throw new Exception("Syntax Error: missing stylesheet declaration.");
                }

                // Find the StylesheetId node.
                XmlNode StylesheetIdNode = stylesheetNode.SelectSingleNode("sss:stylesheetId", namespaceManager);
                if (StylesheetIdNode == null)
                {
                    throw new Exception("Syntax Error: missing StylesheetId declaration.");
                }

                // Find the StylesheetStyle node.
                XmlNode stylesheetTypeCodeNode = stylesheetNode.SelectSingleNode("sss:stylesheetTypeCode", namespaceManager);
                if (stylesheetTypeCodeNode == null)
                {
                    throw new Exception("Syntax Error: missing StylesheetStyle declaration.");
                }

                // Find the name node.
                XmlNode nameNode = stylesheetNode.SelectSingleNode("sss:name", namespaceManager);
                if (nameNode == null)
                {
                    throw new Exception("Syntax Error: missing name declaration.");
                }

                // Extract the data from the XML nodes.
                StylesheetId       = StylesheetIdNode.InnerText;
                stylesheetTypeCode = stylesheetTypeCodeNode.InnerText;
                name = nameNode.InnerText;

                // Remove the stylesheet nodes from the XSL spreadsheet before loading it into the server.
                stylesheetNode.RemoveChild(StylesheetIdNode);
                stylesheetNode.RemoveChild(stylesheetTypeCodeNode);
                stylesheetNode.RemoveChild(nameNode);

                // Create a command to load the stylesheet from the data loaded from the file.
                RemoteBatch    remoteBatch    = new RemoteBatch();
                RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add(assemblyName);
                RemoteType     remoteType     = remoteAssembly.Types.Add(string.Format("{0}.{1}", namespaceName, "Stylesheet"));
                RemoteMethod   remoteMethod   = remoteType.Methods.Add("Load");
                remoteMethod.Parameters.Add("StylesheetId", StylesheetId);
                remoteMethod.Parameters.Add("stylesheetTypeCode", stylesheetTypeCode);
                remoteMethod.Parameters.Add("name", name);
                remoteMethod.Parameters.Add("text", stylesheet.InnerXml);

                // Create a new web client that will serve as the connection point to the server and call the web services to
                // execute the command batch.
                WebClient webClient = new WebClient();
                remoteBatch.Merge(webClient.Execute(remoteBatch));

                // Display the each of the exceptions and set a global flag that shows that there was an exception to the normal
                // execution.
                if (remoteBatch.HasExceptions)
                {
                    foreach (RemoteException exception in remoteBatch.Exceptions)
                    {
                        Console.WriteLine(String.Format("{0}: {1}", remoteMethod.Parameters["StylesheetId"].Value, exception.Message));
                    }
                    hasErrors = true;
                }
            }
            catch (Exception exception)
            {
                // Show the system error and exit with an error.
                Console.WriteLine(exception.Message);
                hasErrors = true;
            }

            // Any errors will cause an abnormal exit.
            if (hasErrors)
            {
                return(1);
            }

            // Display the template that was loaded and exit with a successful code.
            Console.WriteLine(String.Format("{0} Stylesheet: {1}, Loaded", DateTime.Now.ToString("u"), name));
            return(0);
        }
Beispiel #18
0
        /// <summary>
        /// Rebalances an AppraisalModelSet to sector targets.  The model is applied to the aggregate market value of the
        /// account and it's children.
        /// </summary>
        /// <param name="accountId">The parent account to be rebalanced.</param>
        /// <param name="modelId">The sector model to be used.</param>
        /// <returns>A set of proposed orders.</returns>
        public static RemoteBatch Rebalance(ClientMarketData.AccountRow accountRow, ClientMarketData.ModelRow modelRow)
        {
            // Make sure the scheme still exists in the in-memory database.  We need it to rebalance to calculate
            // sector totals.
            ClientMarketData.SchemeRow schemeRow;
            if ((schemeRow = ClientMarketData.Scheme.FindBySchemeId(modelRow.SchemeId)) == null)
            {
                throw new ArgumentException("Scheme doesn't exist in the ClientMarketData", modelRow.SchemeId.ToString());
            }

            // All the market values need to be normalized to a single currency so the sectors can be aggregated. This
            // value is made available to all methods through a member rather than passed on the stack.
            ClientMarketData.CurrencyRow currencyRow = accountRow.CurrencyRow;

            // The final result of this method is a command batch that can be sent to the server.
            RemoteBatch       remoteBatch       = new RemoteBatch();
            RemoteTransaction remoteTransaction = remoteBatch.Transactions.Add();

            // Calculate the total market value for the appraisal and all the sub-accounts.  This will be the denominator
            // in all calculations involving sector percentages.  This feature makes a 'Merge' rebalancer different from a
            // 'Wrap' rebalance.  The 'Wrap' uses the sub-account's market value as the denominator when calculating
            // sector market values.
            decimal accountMarketValue = MarketValue.Calculate(accountRow.CurrencyRow, accountRow,
                                                               MarketValueFlags.EntirePosition | MarketValueFlags.IncludeChildAccounts);

            // The outline of the appraisal will be needed to make calculations based on a position, that is a security,
            // account, position type combination grouped by a security classification scheme.
            AppraisalSet appraisalSet = new Appraisal(accountRow, schemeRow, true);

            // By cycling through all the immediate children of the scheme record, we'll have covered the top-level
            // sectors in this appraisal.
            foreach (AppraisalSet.SchemeRow driverScheme in appraisalSet.Scheme)
            {
                foreach (AppraisalSet.ObjectTreeRow driverTree in driverScheme.ObjectRow.GetObjectTreeRowsByFKObjectObjectTreeParentId())
                {
                    foreach (AppraisalSet.SectorRow driverSector in driverTree.ObjectRowByFKObjectObjectTreeChildId.GetSectorRows())
                    {
                        // The appraisal set collects the ids of the records used.  We need to look up the actual sector
                        // record from the ClientMarketData in order to search through it and aggregate sub-sectors and
                        // securities.
                        ClientMarketData.SectorRow sectorRow = ClientMarketData.Sector.FindBySectorId(driverSector.SectorId);

                        // Get the market value of the top-level sector, including all subaccounts and all positions.
                        decimal actualSectorMarketValue = MarketValue.Calculate(currencyRow, accountRow,
                                                                                sectorRow, MarketValueFlags.EntirePosition | MarketValueFlags.IncludeChildAccounts);

                        // This will find the model percentage of the current top-level sector.  If the sector wasn't
                        // specified in the model, assume a value of zero, which would indicate that we're to sell the
                        // entire sector.
                        ClientMarketData.SectorTargetRow sectorTargetRow =
                            ClientMarketData.SectorTarget.FindByModelIdSectorId(modelRow.ModelId, driverSector.SectorId);
                        decimal targetPercent = sectorTargetRow == null ? 0.0M : sectorTargetRow.Percent;

                        // The target market value is calculated from the model percentage and the actual aggregate
                        // account market value.
                        decimal targetSectorMarketValue = accountMarketValue * targetPercent;

                        // Now that we have a target to shoot for, recursively descend into the structure calculating
                        // propsed orders.
                        RecurseSectors(remoteBatch, remoteTransaction, currencyRow, modelRow, driverSector.ObjectRow,
                                       actualSectorMarketValue, targetSectorMarketValue);
                    }
                }
            }

            // This object holds a complete set of proposed orders to achieve the sector targets in the model.
            return(remoteBatch);
        }
Beispiel #19
0
        /// <summary>
        /// Event handler for changing the name of a label.
        /// </summary>
        /// <param name="sender">The window control that generated the 'LabelEdit' event.</param>
        /// <param name="e">Event Parameters used to control the actions taken by the event handler.</param>
        private void treeView_AfterLabelEdit(object sender, System.Windows.Forms.NodeLabelEditEventArgs e)
        {
            // The TreeView has a bug in it: if you leave the edit mode without typing anything, the returned text of the control
            // will be an empty string. Since we don't want to bother the server or the user with this nonsense, we'll filter out
            // the possiblity here.
            if (e.Label == null)
            {
                e.CancelEdit = true;
                return;
            }

            // Extract the object's properties from the node.
            ObjectNode objectNode = (ObjectNode)e.Node;

            // This command batch is constructed below and sent to the server for execution.
            RemoteBatch remoteBatch = new RemoteBatch();

            // This will insure that table locks are cleaned up.
            try
            {
                // Lock the table
                Debug.Assert(!ClientMarketData.AreLocksHeld);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);

                // Find the object in the data model and make sure it still exists.
                ClientMarketData.ObjectRow objectRow = ClientMarketData.Object.FindByObjectId(objectNode.ObjectId);
                if (objectRow == null)
                {
                    throw new Exception("This object has been deleted.");
                }

                // Construct a command to rename the object.
                RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Core");
                RemoteType     remoteType     = remoteAssembly.Types.Add("Shadows.WebService.Core.Object");
                RemoteMethod   remoteMethod   = remoteType.Methods.Add("Update");
                remoteMethod.Parameters.Add("rowVersion", objectRow.RowVersion);
                remoteMethod.Parameters.Add("objectId", objectRow.ObjectId);
                remoteMethod.Parameters.Add("name", e.Label);
            }
            catch (Exception exception)
            {
                // Write the error and stack trace out to the debug listener
                Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));

                // Cancel the tree operation if we can't execute the command.  The text in the tree control will revert to the
                // previous value.
                e.CancelEdit = true;
            }
            finally
            {
                // Release table locks.
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                Debug.Assert(!ClientMarketData.AreLocksHeld);
            }

            // If the command batch was built successfully, then execute it.  If any part of it should fail, cancel the edit and
            // display the server errors.
            if (remoteBatch != null)
            {
                try
                {
                    // Call the web server to rename the object on the database.  Note that this method must be called when there are
                    // no locks to prevent deadlocking.  That is why it appears in it's own 'try/catch' block.
                    ClientMarketData.Execute(remoteBatch);
                }
                catch (BatchException batchException)
                {
                    // Undo the editing action.  This will restore the name of the object to what it was before the operation.
                    e.CancelEdit = true;

                    // Display each error in the batch.
                    foreach (RemoteException remoteException in batchException.Exceptions)
                    {
                        MessageBox.Show(remoteException.Message, "Quasar Error");
                    }
                }
            }
        }
Beispiel #20
0
        /// <summary>
        /// Creates a command in a RemoteBatch structure to insert a proposed order.
        /// </summary>
        /// <param name="remoteBatch"></param>
        /// <param name="remoteTransaction"></param>
        /// <param name="accountRow"></param>
        /// <param name="securityRow"></param>
        /// <param name="positionTypeCode"></param>
        /// <param name="quantityInstruction"></param>
        private static void Insert(RemoteBatch remoteBatch, RemoteTransaction remoteTransaction,
                                   ClientMarketData.AccountRow accountRow, ClientMarketData.SecurityRow securityRow, int positionTypeCode,
                                   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");
            RemoteType     proposedOrderTreeType = remoteAssembly.Types.Add("Shadows.WebService.Core.ProposedOrderTree");

            // Find the default settlement for this order.
            int settlementId = Shadows.Quasar.Common.Security.GetDefaultSettlementId(securityRow);

            // As a convention between the rebalancing section and the order generation, the parentQuantity passed into this method
            // is a signed value where the negative values are treated as 'Sell' instructions and the positive values meaning
            // 'Buy'. This will adjust the parentQuantity so the trading methods can deal with an unsigned value, which is more
            // natural for trading.
            decimal parentQuantity = Math.Abs(quantityInstruction);

            // This will turn the signed parentQuantity into an absolute parentQuantity and a transaction code (e.g. -1000 is
            // turned into a SELL of 1000 shares).
            int parentTransactionTypeCode = TransactionType.Calculate(securityRow.SecurityTypeCode, 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 parentBlotterId = ClientPreferences.IsBlotterIdNull() ? (accountRow.IsBlotterIdNull() ?
                                                                         TradingSupport.AutoRoute(securityRow, parentQuantity) : accountRow.BlotterId) : ClientPreferences.BlotterId;

            // Create a command to delete the relationship between the parent and child.
            RemoteMethod insertParent = proposedOrderType.Methods.Add("Insert");

            insertParent.Transaction = remoteTransaction;
            insertParent.Parameters.Add("proposedOrderId", DataType.Int, Direction.ReturnValue);
            insertParent.Parameters.Add("blotterId", parentBlotterId);
            insertParent.Parameters.Add("accountId", accountRow.AccountId);
            insertParent.Parameters.Add("securityId", securityRow.SecurityId);
            insertParent.Parameters.Add("settlementId", settlementId);
            insertParent.Parameters.Add("positionTypeCode", positionTypeCode);
            insertParent.Parameters.Add("transactionTypeCode", parentTransactionTypeCode);
            insertParent.Parameters.Add("timeInForceCode", timeInForceCode);
            insertParent.Parameters.Add("orderTypeCode", OrderType.Market);
            insertParent.Parameters.Add("quantity", parentQuantity);

            // Now it's time to create an order for the settlement currency.
            if (securityRow.SecurityTypeCode == SecurityType.Equity || securityRow.SecurityTypeCode == SecurityType.Debt)
            {
                // The underlying currency is needed for the market value calculations.
                ClientMarketData.CurrencyRow currencyRow = MarketData.Currency.FindByCurrencyId(settlementId);

                decimal marketValue = parentQuantity * securityRow.QuantityFactor * Price.Security(currencyRow, securityRow)
                                      * securityRow.PriceFactor * TransactionType.GetCashSign(parentTransactionTypeCode);

                // The stragegy for handling the settlement currency changes is to calculate the old market value, calculate the
                // new market value, and add the difference to the running total for the settlement currency of this security. The
                // new market value is the impact of the trade that was just entered.
                int childTransactionTypeCode = TransactionType.Calculate(securityRow.SecurityTypeCode, positionTypeCode,
                                                                         marketValue);
                decimal childQuantity = Math.Abs(marketValue);

                // The destination blotter comes first from the user preferences, second from the account preferences, and finally
                // uses the auto-routing logic.
                int childBlotterId = ClientPreferences.IsBlotterIdNull() ? (accountRow.IsBlotterIdNull() ?
                                                                            TradingSupport.AutoRoute(currencyRow.SecurityRow, childQuantity) : accountRow.BlotterId) :
                                     ClientPreferences.BlotterId;

                // Fill in the rest of the fields and the defaulted fields for this order. Create a command to delete the
                // relationship between the parent and child.
                RemoteMethod insertChild = proposedOrderType.Methods.Add("Insert");
                insertChild.Transaction = remoteTransaction;
                insertChild.Parameters.Add("proposedOrderId", DataType.Int, Direction.ReturnValue);
                insertChild.Parameters.Add("blotterId", childBlotterId);
                insertChild.Parameters.Add("accountId", accountRow.AccountId);
                insertChild.Parameters.Add("securityId", settlementId);
                insertChild.Parameters.Add("settlementId", settlementId);
                insertChild.Parameters.Add("transactionTypeCode", childTransactionTypeCode);
                insertChild.Parameters.Add("positionTypeCode", positionTypeCode);
                insertChild.Parameters.Add("timeInForceCode", timeInForceCode);
                insertChild.Parameters.Add("orderTypeCode", OrderType.Market);
                insertChild.Parameters.Add("quantity", childQuantity);

                RemoteMethod insertRelation = proposedOrderTreeType.Methods.Add("Insert");
                insertRelation.Transaction = remoteTransaction;
                insertRelation.Parameters.Add("parentId", insertParent.Parameters["proposedOrderId"]);
                insertRelation.Parameters.Add("childId", insertChild.Parameters["proposedOrderId"]);
            }
        }
Beispiel #21
0
        static int Main(string[] args)
        {
            // If this flag is set during the processing of the file, the program will exit with an error code.
            bool hasErrors = false;

            try
            {
                // Defaults
                batchSize     = 100;
                assemblyName  = "Service.External";
                nameSpaceName = "Shadows.WebService.External";

                // The command line parser is driven by different states that are triggered by the flags read.  Unless a flag has been
                // read, the command line parser assumes that it's reading the file name from the command line.
                argumentState = ArgumentState.FileName;

                // Parse the command line for arguments.
                foreach (string argument in args)
                {
                    // Decode the current argument into a state change (or some other action).
                    if (argument == "-a")
                    {
                        argumentState = ArgumentState.Assembly; continue;
                    }
                    if (argument == "-b")
                    {
                        argumentState = ArgumentState.BatchSize; continue;
                    }
                    if (argument == "-n")
                    {
                        argumentState = ArgumentState.NameSpace; continue;
                    }
                    if (argument == "-i")
                    {
                        argumentState = ArgumentState.FileName; continue;
                    }

                    // The parsing state will determine which variable is read next.
                    switch (argumentState)
                    {
                    case ArgumentState.Assembly: assemblyName = argument; break;

                    case ArgumentState.BatchSize: batchSize = Convert.ToInt32(argument); break;

                    case ArgumentState.FileName: fileName = argument; break;

                    case ArgumentState.NameSpace: nameSpaceName = argument; break;
                    }

                    // The default state is to look for the input file name on the command line.
                    argumentState = ArgumentState.FileName;
                }

                // Throw a usage message back at the user if no file name was given.
                if (fileName == null)
                {
                    throw new Exception("Usage: Loader.Algorithm -i <FileName>");
                }

                // Open up the file containing all the broker.
                BrokerReader brokerReader = new BrokerReader(fileName);

                // Create a new web client that will serve as the connection point to the server.
                WebClient webClient = new WebClient();

                // Loading the database involves creating a batch of commands and sending them off as a transaction.  This gives
                // the server a chance to pipeline a large chunk of processing, without completely locking up the server for the
                // entire set of data.  This will construct a header for the command batch which gives information about which
                // assembly contains the class that is used to load the data.
                RemoteBatch       remoteBatch       = new RemoteBatch();
                RemoteTransaction remoteTransaction = remoteBatch.Transactions.Add();
                RemoteAssembly    remoteAssembly    = remoteBatch.Assemblies.Add(assemblyName);
                RemoteType        remoteType        = remoteAssembly.Types.Add(string.Format("{0}.{1}", nameSpaceName, "Broker"));

                // Read the file until an EOF is reached.
                while (true)
                {
                    // This counter keeps track of the number of records sent.  When the batch is full, it's sent to the server to be
                    // executed as a single transaction.
                    int batchCounter = 0;

                    // Read the next broker from the input stream.  A 'null' is returned when we've read past the end of file.
                    Broker broker = brokerReader.ReadBroker();
                    if (broker != null)
                    {
                        // Construct a call to the 'Load' method to populate the broker record.
                        RemoteMethod remoteMethod = remoteType.Methods.Add("Load");
                        remoteMethod.Transaction = remoteTransaction;
                        remoteMethod.Parameters.Add("brokerId", broker.Symbol);
                        remoteMethod.Parameters.Add("name", broker.Name);
                        remoteMethod.Parameters.Add("symbol", broker.Symbol);
                    }

                    // This will check to see if it's time to send the batch.  A batch is sent when the 'batchSize' has been
                    // reached, or if the last record has just been converted into a command.
                    if (++batchCounter % batchSize == 0 || broker == null)
                    {
                        // Call the web services to execute the command batch.
                        remoteBatch.Merge(webClient.Execute(remoteBatch));

                        // Any error during the batch will terminate the execution of the remaining records in the data file.
                        if (remoteBatch.HasExceptions)
                        {
                            // Display each error on the console.
                            foreach (RemoteMethod remoteMethod in remoteBatch.Methods)
                            {
                                foreach (RemoteException remoteException in remoteMethod.Exceptions)
                                {
                                    Console.WriteLine(String.Format("{0}: {1}", remoteMethod.Parameters["brokerId"].Value,
                                                                    remoteException.Message));
                                }
                            }

                            // This will signal the error exit from this loader.
                            hasErrors = true;
                        }

                        // If the end of file was reached, break out of the loop and exit the application.
                        if (broker == null)
                        {
                            break;
                        }

                        // After each batch has been send, check to see if there are additional records to be send.  If so,
                        // regenerate the remote batch and set up the header.
                        remoteBatch       = new RemoteBatch();
                        remoteTransaction = remoteBatch.Transactions.Add();
                        remoteAssembly    = remoteBatch.Assemblies.Add(assemblyName);
                        remoteType        = remoteAssembly.Types.Add(string.Format("{0}.{1}", nameSpaceName, "Broker"));
                    }
                }
            }
            catch (Exception exception)
            {
                // Show the system error and exit with an error.
                Console.WriteLine(exception.Message);
                hasErrors = true;
            }

            // Any errors will cause an abnormal exit.
            if (hasErrors)
            {
                return(1);
            }

            // Write a status message when a the file is loaded successfully.
            Console.WriteLine(String.Format("{0} Data: Brokers, Loaded", DateTime.Now.ToString("u")));

            // If we reached here, the file was imported without issue.
            return(0);
        }
Beispiel #22
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);
            }
        }
Beispiel #23
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);
                }
            }
        }
Beispiel #24
0
        private void DragDropHandler(params object[] arguments)
        {
            ObjectNode toNode    = (ObjectNode)arguments[0];
            ObjectNode fromNode  = (ObjectNode)arguments[1];
            ObjectNode childNode = (ObjectNode)arguments[2];

            // Make sure the user has selected a valid source and destination for the operation.  It's illegal to move the node
            //		1.  To the root of the tree
            //		2.  From the root of the tree
            if (toNode == null || fromNode == null)
            {
                return;
            }

            // Don't allow for circular references.
            try
            {
                // Lock the tables needed for this operation.
                Debug.Assert(!ClientMarketData.AreLocksHeld);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);

                // It's critical that circular references aren't created, either by accident or design.  First, find the object
                // record associated with the destination node.
                ClientMarketData.ObjectRow parentRow = ClientMarketData.Object.FindByObjectId(toNode.ObjectId);
                if (parentRow == null)
                {
                    throw new Exception("This object has been deleted");
                }

                // This is the object that is being dragged.  Find the row
                ClientMarketData.ObjectRow childRow = ClientMarketData.Object.FindByObjectId(childNode.ObjectId);
                if (childRow == null)
                {
                    throw new Exception("This object has been deleted");
                }

                if (Shadows.Quasar.Common.Relationship.IsChildObject(childRow, parentRow))
                {
                    MessageBox.Show(this.TopLevelControl, "This would create a circular references.", "Quasar Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }
            catch (Exception exception)
            {
                // Write the error and stack trace out to the debug listener
                Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));
            }
            finally
            {
                // Release table locks.
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                Debug.Assert(!ClientMarketData.AreLocksHeld);
            }

            // Any commands created below will be constructed in this object and sent to the server for execution.
            RemoteBatch remoteBatch = new RemoteBatch();

            // Change the default model of an account.  When the destination is an account group, account or sub account and the
            // source is a model, a command will be constructed to change the default model.
            if (toNode.ObjectTypeCode == ObjectType.Account && dragNode.ObjectTypeCode == ObjectType.Model)
            {
                try
                {
                    // Lock the tables needed for this operation.
                    Debug.Assert(!ClientMarketData.AreLocksHeld);
                    ClientMarketData.AccountLock.AcquireReaderLock(CommonTimeout.LockWait);

                    // Find the account used, throw an error if it's been deleted.
                    ClientMarketData.AccountRow accountRow;
                    if ((accountRow = ClientMarketData.Account.FindByAccountId(toNode.ObjectId)) == null)
                    {
                        throw new Exception("This account has been deleted");
                    }

                    // Construct a command to change the default model associated with the account.
                    RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Core");
                    RemoteType     remoteType     = remoteAssembly.Types.Add("Shadows.WebService.Core.Account");
                    RemoteMethod   remoteMethod   = remoteType.Methods.Add("Update");
                    remoteMethod.Parameters.Add("rowVersion", accountRow.RowVersion);
                    remoteMethod.Parameters.Add("accountId", accountRow.AccountId);
                    remoteMethod.Parameters.Add("modelId", dragNode.ObjectId);
                }
                catch (Exception exception)
                {
                    // Write the error and stack trace out to the debug listener
                    Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));
                }
                finally
                {
                    // Release table locks.
                    if (ClientMarketData.AccountLock.IsReaderLockHeld)
                    {
                        ClientMarketData.AccountLock.ReleaseReaderLock();
                    }
                    Debug.Assert(!ClientMarketData.AreLocksHeld);
                }
            }
            else
            {
                // If we made it here, the drag-and-drop is interpreted as a command to move a child from one parent to another.
                try
                {
                    // Lock the tables needed for this operation.
                    Debug.Assert(!ClientMarketData.AreLocksHeld);
                    ClientMarketData.ObjectTreeLock.AcquireReaderLock(CommonTimeout.LockWait);

                    // Extract the primary identifiers from the user interface nodes.
                    int fromId  = fromNode.ObjectId;
                    int toId    = toNode.ObjectId;
                    int childId = dragNode.ObjectId;

                    // Find the object in the data model and make sure it still exists.
                    ClientMarketData.ObjectTreeRow objectTreeRow = ClientMarketData.ObjectTree.FindByParentIdChildId(fromNode.ObjectId, dragNode.ObjectId);
                    if (objectTreeRow == null)
                    {
                        throw new Exception("This relationship has been deleted by someone else.");
                    }

                    // Moving a child object from one parent to another must be accomplished as a transaction.  Otherwise, an
                    // orhpan object will be created if the operation fails midway through.
                    RemoteTransaction remoteTransaction = remoteBatch.Transactions.Add();
                    RemoteAssembly    remoteAssembly    = remoteBatch.Assemblies.Add("Service.Core");
                    RemoteType        remoteType        = remoteAssembly.Types.Add("Shadows.WebService.Core.ObjectTree");

                    // Construct a command delete the old parent relation.
                    RemoteMethod deleteObjectTree = remoteType.Methods.Add("Delete");
                    deleteObjectTree.Transaction = remoteTransaction;
                    deleteObjectTree.Parameters.Add("rowVersion", objectTreeRow.RowVersion);
                    deleteObjectTree.Parameters.Add("parentId", fromId);
                    deleteObjectTree.Parameters.Add("childId", childId);

                    // Construct a command insert a new parent relation.
                    RemoteMethod insertObjectTree = remoteType.Methods.Add("Insert");
                    insertObjectTree.Transaction = remoteTransaction;
                    insertObjectTree.Parameters.Add("parentId", toId);
                    insertObjectTree.Parameters.Add("childId", childId);
                }
                catch (Exception exception)
                {
                    // Write the error and stack trace out to the debug listener
                    Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));
                }
                finally
                {
                    // Release table locks.
                    if (ClientMarketData.ObjectTreeLock.IsReaderLockHeld)
                    {
                        ClientMarketData.ObjectTreeLock.ReleaseReaderLock();
                    }
                    Debug.Assert(!ClientMarketData.AreLocksHeld);
                }
            }

            // If the command batch was built successfully, then execute it.
            if (remoteBatch != null)
            {
                try
                {
                    // Call the web server to rename the object on the database.  Note that this method must be called when there are
                    // no locks to prevent deadlocking.  That is why it appears in it's own 'try/catch' block.
                    ClientMarketData.Execute(remoteBatch);
                }
                catch (BatchException batchException)
                {
                    // Display each error in the batch.
                    foreach (RemoteException remoteException in batchException.Exceptions)
                    {
                        MessageBox.Show(remoteException.Message, "Quasar Error");
                    }
                }
            }
        }
Beispiel #25
0
        /// <summary>
        /// Execute a command batch and synchronizes the client data model with the newer records from the server.
        /// </summary>
        public static void Execute(RemoteBatch remoteBatch)
        {
            // This 'try' block will insure that the mutual exclusion locks are released.
            try
            {
                // Maure sure only one thread at a time tries to refresh the data model.
                ClientMarketData.refreshMutex.WaitOne();

                // IMPORTANT CONCEPT: The rowVersion keeps track of the state of the client in-memory database. The server returns
                // a value for us to use on the next cycle.  If, for any reason, the merge of the data on the client should fail,
                // we won't use the new value on the next cycle. That is, we're going to keep on asking for the same incremental
                // set of records until we've successfully merged them.  This guarantees that the client and server databases stay
                // consistent with each other.
                DateTime timeStamp  = ClientMarketData.timeStamp;
                long     rowVersion = ClientMarketData.rowVersion;

                // IMPORTANT CONCEPT:  Executing the 'Reconcile' Web Service with a rowVersion returns to the client a DataSet with
                // only records that are the same age or younger than the rowVersion. This reduces the traffic on the network to
                // include only the essential records.  This set also contains the deleted records.  When the DataSet that is
                // returned from this Web Service is merged with the current data, the client will be reconciled with the server as
                // of the 'rowVersion' returned from the server.
                DataSet   resultSet;
                WebClient webClient = new WebClient();
                DataSet   dataSet   = webClient.ExecuteAndReconcile(ref timeStamp, ref rowVersion, remoteBatch, out resultSet);
                remoteBatch.Merge(resultSet);

                // If the time stamps are out of sync, then the server has reset since our last refresh (or this is the first time
                // refreshing the data mdoel).  This will reset the client side of the data model so that, after this refresh, the
                // client and the server will be in sync again.
                if (ClientMarketData.timeStamp != timeStamp)
                {
                    ClientMarketData.rowVersion = 0;
                    ClientMarketData.timeStamp  = timeStamp;
                    ClientMarketData.Clear();
                }

                // Optimization: Don't merge the results if there's nothing to merge.
                if (rowVersion > ClientMarketData.rowVersion)
                {
                    // IMPORTANT CONCEPT: This broadcast can be used to set up conditions for the data event handlers.  Often,
                    // optimizing algorithms will be used to consolidate the results of a merge.  This will allow the event driven
                    // logic to clear previous results and set up initial states for handling the bulk update of data.
                    ClientMarketData.OnBeginMerge(typeof(ClientMarketData));

                    // This 'try' block will insure that the locks are released if there's an error.
                    try
                    {
                        // IMPORTANT CONCEPT: Make sure that there aren't any nested locks.  Table locks have to be aquired in the
                        // same order for every thread that uses the shared data model.  It's possible that the current thread may
                        // have locked table 'B' if the preamble, then try to lock table 'A' during the processing of a command
                        // batch.  If another thread aquires the lock on table 'A' and blocks on table 'B', we will have a
                        // deadlock.  This is designed to catch situations where the 'Execute' method is called while tables are
                        // already locked.
                        Debug.Assert(!ClientMarketData.AreLocksHeld);

                        // IMPORTANT CONCEPT: Since the results will still be on the server if the client misses a refresh cycle,
                        // we take the attitude that this update process doesn't have to wait for locks. That is, if we can't get
                        // all the tables locked quickly, we'll just wait until the next refresh period to get the results. This
                        // effectively prevents deadlocking on the client. Make sure all the tables are locked before populating
                        // them.
                        foreach (TableLock tableLock in ClientMarketData.TableLocks)
                        {
                            tableLock.AcquireWriterLock(ClientTimeout.LockWait);
                        }

                        // IMPORANT CONCEPT:  Once all the write locks have been obtained, we can merge the results.  This will
                        // trigger the events associated with the tables for updated and deleted rows.  Also, if
                        // "AcceptChanges" is invoked for a DataSet or a Table, every single record in the DataSet or DataTable
                        // will be "Committed", even though they are unchanged.  This is a VERY inefficient operation.  To get
                        // around this, an ArrayList of modified records is constructed during the Merge operation.  After the
                        // merge, only the new records are committed.
                        ClientMarketData.mergedRows.Clear();
                        ClientMarketData.Merge(dataSet);
                        for (int index = 0; index < ClientMarketData.mergedRows.Count; index++)
                        {
                            ((DataRow)ClientMarketData.mergedRows[index]).AcceptChanges();
                        }

                        // If the merge operation was successful, then we can use the new rowVersion for the next cycle. Any
                        // exception before this point will result in a request of the same set of data becaue the rowVersion was
                        // never updated.
                        ClientMarketData.rowVersion = rowVersion;
                    }
                    catch (ConstraintException)
                    {
                        // Write out the exact location of the error.
                        foreach (DataTable dataTable in ClientMarketData.Tables)
                        {
                            foreach (DataRow dataRow in dataTable.Rows)
                            {
                                if (dataRow.HasErrors)
                                {
                                    Console.WriteLine("Error in '{0}': {1}", dataRow.Table.TableName, dataRow.RowError);
                                }
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        // Write the error and stack trace out to the debug listener
                        Debug.WriteLine(String.Format("{0}, {1}", exception.Message, exception.StackTrace));
                    }
                    finally
                    {
                        // No matter what happens above, we need to release the locks acquired above.
                        foreach (TableLock tableLock in ClientMarketData.TableLocks)
                        {
                            if (tableLock.IsWriterLockHeld)
                            {
                                tableLock.ReleaseWriterLock();
                            }
                        }
                    }

                    // IMPORTANT CONCEPT: When the merge is complete and the tables are unlocked, this will broadcast an event
                    // which allows optimization code to consolidate the results, examine the changed values and update reports
                    // based on the changed data.
                    ClientMarketData.OnEndMerge(typeof(ClientMarketData));
                }
            }
            finally
            {
                // Other threads can now request a refresh of the data model.
                ClientMarketData.refreshMutex.ReleaseMutex();
            }

            // Throw a specialized exception if the server returned any errors in the RemoteBatch structure.
            if (remoteBatch.HasExceptions)
            {
                throw new BatchException(remoteBatch);
            }
        }
Beispiel #26
0
 static CommandBatch()
 {
     CommandBatch.remoteBatch = new RemoteBatch();
 }
Beispiel #27
0
        /// <summary>
        /// Rebalances an account to the sector targets, then recursively rebalances the children accounts.
        /// </summary>
        /// <param name="orderFormBuilder">A collection of orders.</param>
        /// <param name="accountRow">The parent account to be rebalanced.</param>
        /// <param name="modelRow">The model containing the sector targets.</param>
        /// <param name="schemeRow">The outline scheme used to define the sector contents.</param>
        private static void RecurseAccounts(RemoteBatch remoteBatch, RemoteTransaction remoteTransaction,
                                            ClientMarketData.AccountRow accountRow, ClientMarketData.ModelRow modelRow, ClientMarketData.SchemeRow schemeRow)
        {
            // All the market values of all the securities in this account are normalized to a single currency so they can
            // be aggregated.
            ClientMarketData.CurrencyRow currencyRow = ClientMarketData.Currency.FindByCurrencyId(accountRow.CurrencyId);

            // Calculate the total market value for the appraisal without including child accounts.  This is a 'Wrap'
            // rebalancing, so we're only concerned with what's in this account.  The account's market value will be the
            // denominator in all calculations involving sector percentages.
            decimal accountMarketValue = MarketValue.Calculate(currencyRow, accountRow,
                                                               MarketValueFlags.EntirePosition);

            // The outline of the appraisal will be needed to make market value calculations based on a sector.  Note that
            // we're not including the child accounts in the outline.  Wrap rebalancing works only on a single account at
            // a time.
            AppraisalSet appraisalSet = new Appraisal(accountRow, schemeRow, false);

            // By cycling through all the immediate children of the scheme record, we'll have covered the top-level
            // sectors in this appraisal.
            foreach (AppraisalSet.SchemeRow driverScheme in appraisalSet.Scheme)
            {
                foreach (AppraisalSet.ObjectTreeRow driverTree in
                         driverScheme.ObjectRow.GetObjectTreeRowsByFKObjectObjectTreeParentId())
                {
                    foreach (AppraisalSet.SectorRow driverSector in
                             driverTree.ObjectRowByFKObjectObjectTreeChildId.GetSectorRows())
                    {
                        // Find the sectors row record that corresponds to the current sector in the appraisal set.
                        ClientMarketData.SectorRow sectorRow = ClientMarketData.Sector.FindBySectorId(driverSector.SectorId);

                        // Get the market value of the top-level sector, including all sub-sectors and all positions
                        // belonging to only the current account.
                        decimal actualSectorMarketValue = MarketValue.Calculate(currencyRow, accountRow, sectorRow,
                                                                                MarketValueFlags.EntirePosition);

                        // This will find the model percentage of the current top-level sector.  If the sector wasn't
                        // specified in the model, assume a value of zero, which would indicate that we're to sell the
                        // entire sector.
                        ClientMarketData.SectorTargetRow sectorTargetRow =
                            ClientMarketData.SectorTarget.FindByModelIdSectorId(modelRow.ModelId, driverSector.SectorId);
                        decimal targetPercent = (sectorTargetRow == null) ? 0.0M : sectorTargetRow.Percent;

                        // The sector's target market value is calculated from the model percentage and the current
                        // account market value.  This is placed in a member variable so it's available to the methods
                        // when we recurse.
                        decimal targetSectorMarketValue = accountMarketValue * targetPercent;

                        // Now that we have a sector target to shoot for, recursively descend into the structure
                        // calculating proposed orders.
                        SectorWrap.RecurseSectors(remoteBatch, remoteTransaction, modelRow, driverSector, actualSectorMarketValue,
                                                  targetSectorMarketValue);
                    }
                }
            }

            // 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())
                {
                    SectorWrap.RecurseAccounts(remoteBatch, remoteTransaction, childAccount, modelRow, schemeRow);
                }
            }
        }
Beispiel #28
0
        public static void Distribute(int blockOrderId)
        {
            // This batch will be filled in with the allocations.
            RemoteBatch remoteBatch = null;

            try
            {
                // Lock all the tables that we'll reference while building a blotter document.
                Debug.Assert(!ClientMarketData.AreLocksHeld);
                ClientMarketData.AllocationLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.BlockOrderLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.ExecutionLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.OrderLock.AcquireReaderLock(CommonTimeout.LockWait);

                // Find the block order that is to be allocated.
                ClientMarketData.BlockOrderRow blockOrderRow = ClientMarketData.BlockOrder.FindByBlockOrderId(blockOrderId);
                if (blockOrderRow == null)
                {
                    throw new Exception(String.Format("Block Id {0} doesn't exist", blockOrderId));
                }

                // Aggregate the total quantity ordered.  This becomes the demoninator for the pro-rata calculation.
                decimal orderedQuantity = 0.0M;
                foreach (ClientMarketData.OrderRow orderRow in blockOrderRow.GetOrderRows())
                {
                    orderedQuantity += orderRow.Quantity;
                }

                // These values will total up all the executions posted against this block order.  The pro-rata
                // allocation will divide all the executions up against the ratio of the quantity ordered against the
                // total quantity ordered.  The price is an average price of all the executions.
                decimal  executedQuantity        = 0.0M;
                decimal  executedPrice           = 0.0M;
                decimal  executedCommission      = 0.0M;
                decimal  executedAccruedInterest = 0.0M;
                decimal  executedUserFee0        = 0.0M;
                decimal  executedUserFee1        = 0.0M;
                decimal  executedUserFee2        = 0.0M;
                decimal  executedUserFee3        = 0.0M;
                DateTime tradeDate      = DateTime.MinValue;
                DateTime settlementDate = DateTime.MinValue;

                // Total up all the executions against this block.
                foreach (ClientMarketData.ExecutionRow executionRow in blockOrderRow.GetExecutionRows())
                {
                    executedQuantity        += executionRow.Quantity;
                    executedPrice           += executionRow.Price * executionRow.Quantity;
                    executedCommission      += executionRow.Commission;
                    executedAccruedInterest += executionRow.AccruedInterest;
                    executedUserFee0        += executionRow.UserFee0;
                    executedUserFee1        += executionRow.UserFee1;
                    executedUserFee2        += executionRow.UserFee2;
                    executedUserFee3        += executionRow.UserFee3;
                    tradeDate      = executionRow.TradeDate;
                    settlementDate = executionRow.SettlementDate;
                }

                // Calculate the average price.
                decimal averagePrice = Math.Round((executedQuantity > 0.0M) ? executedPrice / executedQuantity : 0.0M, 2);

                // These values are used to keep track of how much has been allocated.  Because of the nature of a
                // pro-rata allocation, there will be an odd remainder after the allocation is finished.  We will
                // arbitrarily pick the last order in the block order and give it the remainer of the order.  To do that,
                // totals have to be kept of all the allocations that have been created before the last one.
                decimal allocatedQuantity        = 0.0M;
                decimal allocatedCommission      = 0.0M;
                decimal allocatedAccruedInterest = 0.0M;
                decimal allocatedUserFee0        = 0.0M;
                decimal allocatedUserFee1        = 0.0M;
                decimal allocatedUserFee2        = 0.0M;
                decimal allocatedUserFee3        = 0.0M;

                // Put all the allocations in a single batch.
                remoteBatch = new RemoteBatch();
                RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Core");
                RemoteType     remoteType     = remoteAssembly.Types.Add("Shadows.WebService.Core.Allocation");

                // Allocate the order back to the original accounts.  Because odd values can be generated when dividing by the
                // pro-rata value, the last order will get the remaining portions of the execution.
                int orderCounter = blockOrderRow.GetOrderRows().Length;
                foreach (ClientMarketData.OrderRow orderRow in blockOrderRow.GetOrderRows())
                {
                    decimal quantity;
                    decimal commission;
                    decimal accruedInterest;
                    decimal userFee0;
                    decimal userFee1;
                    decimal userFee2;
                    decimal userFee3;

                    // The last account in the order is arbitrarily given the remaining parts of the execution.
                    if (--orderCounter == 0)
                    {
                        quantity        = executedQuantity - allocatedQuantity;
                        commission      = executedCommission - allocatedCommission;
                        accruedInterest = executedAccruedInterest = allocatedAccruedInterest;
                        userFee0        = executedUserFee0 - allocatedUserFee0;
                        userFee1        = executedUserFee1 - allocatedUserFee1;
                        userFee2        = executedUserFee2 - allocatedUserFee2;
                        userFee3        = executedUserFee3 - allocatedUserFee3;
                    }
                    else
                    {
                        // Calcuation the proportion of the trade destined for the current order.  The proportion is
                        // based on the amount of the original order against the block total.
                        quantity        = Math.Round(executedQuantity * orderRow.Quantity / orderedQuantity, 0);
                        commission      = Math.Round(executedCommission * orderRow.Quantity / orderedQuantity, 2);
                        accruedInterest = Math.Round(executedAccruedInterest * orderRow.Quantity / orderedQuantity, 2);
                        userFee0        = Math.Round(executedUserFee0 * orderRow.Quantity / orderedQuantity, 2);
                        userFee1        = Math.Round(executedUserFee1 * orderRow.Quantity / orderedQuantity, 2);
                        userFee2        = Math.Round(executedUserFee2 * orderRow.Quantity / orderedQuantity, 2);
                        userFee3        = Math.Round(executedUserFee3 * orderRow.Quantity / orderedQuantity, 2);
                    }

                    // Keep a running total of the amount allocated so far.  This will be used to calculate the last order's
                    // portion when the loop has finished.
                    allocatedQuantity        += quantity;
                    allocatedCommission      += commission;
                    allocatedAccruedInterest += accruedInterest;
                    allocatedUserFee0        += userFee0;
                    allocatedUserFee1        += userFee1;
                    allocatedUserFee2        += userFee2;
                    allocatedUserFee3        += userFee3;

                    // If the allocation has a positive quantity to register, then post it to the server.
                    if (quantity > 0.0M)
                    {
                        // Call the web service to add the new execution.
                        RemoteMethod remoteMethod = remoteType.Methods.Add("Insert");
                        remoteMethod.Parameters.Add("blockOrderId", orderRow.BlockOrderId);
                        remoteMethod.Parameters.Add("accountId", orderRow.AccountId);
                        remoteMethod.Parameters.Add("securityId", orderRow.SecurityId);
                        remoteMethod.Parameters.Add("settlementId", orderRow.SettlementId);
                        remoteMethod.Parameters.Add("positionTypeCode", orderRow.PositionTypeCode);
                        remoteMethod.Parameters.Add("transactionTypeCode", orderRow.TransactionTypeCode);
                        remoteMethod.Parameters.Add("quantity", quantity);
                        remoteMethod.Parameters.Add("price", averagePrice);
                        remoteMethod.Parameters.Add("commission", commission);
                        remoteMethod.Parameters.Add("accruedInterest", accruedInterest);
                        remoteMethod.Parameters.Add("userFee0", userFee0);
                        remoteMethod.Parameters.Add("userFee1", userFee1);
                        remoteMethod.Parameters.Add("userFee2", userFee2);
                        remoteMethod.Parameters.Add("userFee3", userFee3);
                        remoteMethod.Parameters.Add("tradeDate", tradeDate);
                        remoteMethod.Parameters.Add("settlementDate", settlementDate);
                        remoteMethod.Parameters.Add("createdTime", DateTime.Now);
                        remoteMethod.Parameters.Add("createdLoginId", ClientPreferences.LoginId);
                        remoteMethod.Parameters.Add("modifiedTime", DateTime.Now);
                        remoteMethod.Parameters.Add("modifiedLoginId", ClientPreferences.LoginId);
                    }
                }
            }
            catch (Exception exception)
            {
                // This signals that the batch isn't valid and shouldn't be sent.
                remoteBatch = null;

                // This will catch all remaining exceptions.
                Debug.WriteLine(exception.Message);
            }
            finally
            {
                // Release the locks obtained to produce the blotter report.
                if (ClientMarketData.AllocationLock.IsReaderLockHeld)
                {
                    ClientMarketData.AllocationLock.ReleaseReaderLock();
                }
                if (ClientMarketData.BlockOrderLock.IsReaderLockHeld)
                {
                    ClientMarketData.BlockOrderLock.ReleaseReaderLock();
                }
                if (ClientMarketData.ExecutionLock.IsReaderLockHeld)
                {
                    ClientMarketData.ExecutionLock.ReleaseReaderLock();
                }
                if (ClientMarketData.OrderLock.IsReaderLockHeld)
                {
                    ClientMarketData.OrderLock.ReleaseReaderLock();
                }
                Debug.Assert(!ClientMarketData.AreLocksHeld);
            }

            // Once the locks are release, the batch can be sent to the server.
            if (remoteBatch != null)
            {
                ClientMarketData.Send(remoteBatch);
            }
        }
Beispiel #29
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);
                }
            }
        }
Beispiel #30
0
        public void Initialize(Account account, Security security, TransactionType transactionType, TIF tif,
                               PricedAt pricedAt, decimal quantity, object price1, object price2)
        {
            // Create a block order on the server.
            RemoteBatch    remoteBatch    = new RemoteBatch();
            RemoteAssembly remoteAssembly = remoteBatch.Assemblies.Add("Service.Trading");
            RemoteType     remoteType     = remoteAssembly.Types.Add("Shadows.WebService.Trading.Order");
            RemoteMethod   remoteMethod   = remoteType.Methods.Add("Insert");

            remoteMethod.Parameters.Add("orderId", DataType.Int, Direction.ReturnValue);
            remoteMethod.Parameters.Add("accountId", account.AccountId);
            remoteMethod.Parameters.Add("securityId", security.SecurityId);
            remoteMethod.Parameters.Add("settlementId", security.SettlementId);
            remoteMethod.Parameters.Add("transactionTypeCode", (int)transactionType);
            remoteMethod.Parameters.Add("timeInForceCode", (int)tif);
            remoteMethod.Parameters.Add("orderTypeCode", (int)pricedAt);
            remoteMethod.Parameters.Add("quantity", quantity);
            remoteMethod.Parameters.Add("price1", price1 == null ? (object)DBNull.Value : price1);
            remoteMethod.Parameters.Add("price2", price2 == null ? (object)DBNull.Value : price2);
            ClientMarketData.Execute(remoteBatch);

            // Now that the block order is created, construct the in-memory version of the record.
            int orderId = (int)remoteMethod.Parameters["orderId"].Value;

            try
            {
                // Lock the tables.
                Debug.Assert(!ClientMarketData.AreLocksHeld);
                ClientMarketData.AccountLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.OrderLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait);
                ClientMarketData.SecurityLock.AcquireReaderLock(CommonTimeout.LockWait);

                ClientMarketData.OrderRow orderRow = ClientMarketData.Order.FindByOrderId(orderId);
                if (orderRow == null)
                {
                    throw new Exception(String.Format("Order {0} doesn't exist", orderId));
                }

                Initialize(orderRow);
            }
            finally
            {
                // Release the table locks.
                if (ClientMarketData.AccountLock.IsReaderLockHeld)
                {
                    ClientMarketData.AccountLock.ReleaseReaderLock();
                }
                if (ClientMarketData.OrderLock.IsReaderLockHeld)
                {
                    ClientMarketData.OrderLock.ReleaseReaderLock();
                }
                if (ClientMarketData.ObjectLock.IsReaderLockHeld)
                {
                    ClientMarketData.ObjectLock.ReleaseReaderLock();
                }
                if (ClientMarketData.SecurityLock.IsReaderLockHeld)
                {
                    ClientMarketData.SecurityLock.ReleaseReaderLock();
                }
                Debug.Assert(!ClientMarketData.AreLocksHeld);
            }
        }