/// <summary> /// Collect the metadata from the data model. /// </summary> /// <param name="state">The generic thread start parameter.</param> void CalculateMetadata() { // Copy the values from the data model into the metadata. DataModel.EntityRow entityRow = DataModel.Entity.EntityKey.Find(this.EntityId); this.CreatedTime = entityRow.CreatedTime; this.ModifiedTime = entityRow.ModifiedTime; }
/// <summary> /// Handles a change to a Entity row. /// </summary> /// <param name="sender">The Object that originated the event.</param> /// <param name="entityRowChangeEventArgs">The event arguments.</param> void OnEntityRowChanged(Object sender, DataModel.EntityRowChangeEventArgs entityRowChangeEventArgs) { // We're only interested in changes that affect this Entity. When the created or modified dates change, update the related properties in the MVVM. if (entityRowChangeEventArgs.Action == DataRowAction.Change) { DataModel.EntityRow entityRow = entityRowChangeEventArgs.Row; if (entityRow.EntityId == this.BlotterId) { this.CreatedTime = entityRow.CreatedTime; this.ModifiedTime = entityRow.ModifiedTime; } } }
/// <summary> /// Handles a change to a Entity row. /// </summary> /// <param name="sender">The Object that originated the event.</param> /// <param name="entityRowChangeEventArgs">The event arguments.</param> void OnEntityRowChanged(Object sender, DataModel.EntityRowChangeEventArgs entityRowChangeEventArgs) { // We're only interested in changes that affect this Entity. if (entityRowChangeEventArgs.Action == DataRowAction.Change) { DataModel.EntityRow entityRow = entityRowChangeEventArgs.Row; if (entityRow.EntityId == this.EntityId) { this.CreatedTime = entityRow.CreatedTime; this.ModifiedTime = entityRow.ModifiedTime; } } }
/// <summary> /// Create an debt working order. /// </summary> void CreateDebt() { // All orders get a unique identifier. Guid workingOrderId = Guid.NewGuid(); // These records provide the starting point for generating the orders. DataModel.BlotterRow blotterRow = DataModel.Blotter.BlotterKey.Find(generatorInfo.BlotterId); DataModel.UserRow userRow = DataModel.User.UserKey.Find(generatorInfo.UserId); DataModel.CountryRow unitedStatesRow = DataModel.Country.CountryKeyExternalId0.Find("US"); DataModel.StatusRow statusRow = DataModel.Status.StatusKey.Find(StatusCode.New); // Generate the settlement currency DataModel.EntityRow usdEntityRow = DataModel.Entity.EntityKeyExternalId0.Find("USD"); DataModel.SecurityRow settlementCurrencyRow = DataModel.Security.SecurityKey.Find(usdEntityRow.EntityId); // The orders are an even mix of Buys and Sells. Most positions are long. Boolean isBuy = random.Next(2) == 0; Boolean isLong = random.Next(4) != 0; SideCode sideCode = isBuy && isLong ? SideCode.Buy : !isBuy && isLong ? SideCode.Sell : isBuy && !isLong ? SideCode.BuyCover : SideCode.SellShort; DataModel.SideRow sideRow = DataModel.Side.SideKey.Find(sideCode); // Find a random debt position that is unique to this blotter. DataModel.SecurityRow securityRow = null; while (securityRow == null) { // Select a random debt instrument for the next order. DataModel.DebtRow debtRow = DataModel.Debt[random.Next(DataModel.Debt.Count - 1)]; // Only generate orders for positions that are unique to this blotter. Position position = new Position(debtRow.DebtId, sideCode); if (!positionSet.Contains(position)) { securityRow = debtRow.SecurityRowByFK_Security_Debt_DebtId; positionSet.Add(position); } } // These orders will not match by default. We need to turn them on manually. DataModel.CrossingRow crossingRow = DataModel.Crossing.CrossingKey.Find(CrossingCode.NeverMatch); // Select a random Time In Force for this order. Most orders are Day orders but occationally we'll generate a GTC just to keep it interesting. TimeInForceCode timeInForce = random.Next(4) == 0 ? TimeInForceCode.GoodTillCancel : TimeInForceCode.Day; DataModel.TimeInForceRow timeInForceRow = DataModel.TimeInForce.TimeInForceKey.Find(timeInForce); // Generate the trade and settlement dates based on the current time and make sure it doesn't fall on a weekend. DateTime tradeDate = DateTime.Now; DateTime settlementDate = DateTime.Now; TimeSpan oneDay = TimeSpan.FromDays(1.0); for (Int32 dayIndex = 0; dayIndex < 3; dayIndex++) { settlementDate += oneDay; if (settlementDate.DayOfWeek == DayOfWeek.Saturday) { settlementDate += oneDay; } if (settlementDate.DayOfWeek == DayOfWeek.Sunday) { settlementDate += oneDay; } } // This will generate random matching preferences for the orders for demonstrating the matching box capabilities. Boolean isBrokerMatch = random.Next(20) == 0; Boolean isHedgeMatch = random.Next(15) == 0; Boolean isInstitutionMatch = true; // This randomizes the random matching patterns. Every now and then, don't match with anyone. if (random.Next(5) == 0) { isBrokerMatch = false; isHedgeMatch = false; isInstitutionMatch = false; } // <transaction> XElement elementTransaction = new XElement("transaction"); this.xDocument.Root.Add(elementTransaction); // <method name="StoreWorkingOrder"> XElement elementWorkingOrder = new XElement("method", new XAttribute("name", "StoreWorkingOrder")); elementTransaction.Add(elementWorkingOrder); // <parameter name="blotterKey" value="EMERGING MARKETS BLOTTER" /> elementWorkingOrder.Add( new XElement("parameter", new XAttribute("name", "blotterKey"), new XAttribute("value", blotterRow.EntityRow.ExternalId0))); // <parameter name="configurationId" value="US TICKER" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "configurationId"), new XAttribute("value", "CUSIP"))); // <parameter name="createdTime" value="5/6/2012 5:27:56 PM" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "createdTime"), new XAttribute("value", DateTime.Now.ToString("G")))); // <parameter name="crossingKey" value="NEVER MATCH" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "crossingKey"), new XAttribute("value", crossingRow.ExternalId0))); // <parameter name="externalId0" value="{bab88942-5c4e-440a-a352-c8e9b00fec12}" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "externalId0"), new XAttribute("value", workingOrderId.ToString("B")))); // <parameter name="isBrokerMatch" value="false" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "isBrokerMatch"), new XAttribute("value", isBrokerMatch))); // <parameter name="isHedgeMatch" value="false" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "isHedgeMatch"), new XAttribute("value", isHedgeMatch))); // <parameter name="isInstitutionMatch" value="true" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "isInstitutionMatch"), new XAttribute("value", isInstitutionMatch))); // <parameter name="modifiedTime" value="5/6/2012 5:27:56 PM" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "modifiedTime"), new XAttribute("value", DateTime.Now.ToString("G")))); // <parameter name="orderTypeKey" value="MKT" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "orderTypeKey"), new XAttribute("value", "MKT"))); // <parameter name="securityKeyBySecurityId" value="ODP" /> elementWorkingOrder.Add( new XElement("parameter", new XAttribute("name", "securityKeyBySecurityId"), new XAttribute("value", securityRow.EntityRow.ExternalId4))); // <parameter name="securityKeyBySettlementId" value="USD" /> elementWorkingOrder.Add( new XElement("parameter", new XAttribute("name", "securityKeyBySettlementId"), new XAttribute("value", settlementCurrencyRow.EntityRow.ExternalId0))); // <parameter name="settlementDate" value="5/9/2012 5:27:56 PM" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "settlementDate"), new XAttribute("value", settlementDate.ToString("G")))); // <parameter name="sideKey" value="SELL" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "sideKey"), new XAttribute("value", sideRow.ExternalId0))); // <parameter name="statusKey" value="NEW" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "statusKey"), new XAttribute("value", statusRow.ExternalId0))); // <parameter name="timeInForceKey" value="DAY" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "timeInForceKey"), new XAttribute("value", timeInForceRow.ExternalId0))); // <parameter name="tradeDate" value="5/6/2012 5:27:56 PM" /> elementWorkingOrder.Add(new XElement("parameter", new XAttribute("name", "tradeDate"), new XAttribute("value", tradeDate.ToString("G")))); // <parameter name="userKeyByCreatedUserId" value="DEV KAPOOR" /> elementWorkingOrder.Add( new XElement("parameter", new XAttribute("name", "userKeyByCreatedUserId"), new XAttribute("value", userRow.EntityRow.ExternalId0))); // <parameter name="userKeyByModifiedUserId" value="DEV KAPOOR" /> elementWorkingOrder.Add( new XElement("parameter", new XAttribute("name", "userKeyByModifiedUserId"), new XAttribute("value", userRow.EntityRow.ExternalId0))); // This will generate between one and three source orders for the working order. Source orders are a blocking concept. You can get several orders for // the same security on the same side for the same price. When this happens, it is much more efficient to block them as a single order and execute them // as a single order and allocate them back to the original orders when the order is done. Int32 sourceOrderCount = random.Next(1, 3); for (Int32 sourceOrderIndex = 0; sourceOrderIndex < sourceOrderCount; sourceOrderIndex++) { // This creates a unique identifier for the source order. Guid sourceOrderId = Guid.NewGuid(); // This generates a random quantity for the order between 100 and 10,000 shares. Decimal orderedQuantity = Convert.ToDecimal(random.Next(1, 100)) * 100.0M; // <method name="StoreSourceOrder"> XElement elementSourceOrder = new XElement("method", new XAttribute("name", "StoreSourceOrder")); elementTransaction.Add(elementSourceOrder); // <parameter name="configurationId" value="US TICKER" /> elementSourceOrder.Add(new XElement("parameter", new XAttribute("name", "configurationId"), new XAttribute("value", "CUSIP"))); // <parameter name="createdTime" value="2012-05-06T17:27:56.2658093-04:00" /> elementSourceOrder.Add(new XElement("parameter", new XAttribute("name", "createdTime"), new XAttribute("value", DateTime.Now))); // <parameter name="externalId0" value="{3c69e0a0-3316-4499-a7b1-6dda5a058837}" /> elementSourceOrder.Add(new XElement("parameter", new XAttribute("name", "externalId0"), new XAttribute("value", sourceOrderId.ToString("B")))); // <parameter name="modifiedTime" value="5/6/2012 5:27:56 PM" /> elementSourceOrder.Add(new XElement("parameter", new XAttribute("name", "modifiedTime"), new XAttribute("value", DateTime.Now.ToString("G")))); // <parameter name="orderedQuantity" value="4300.0" /> elementSourceOrder.Add(new XElement("parameter", new XAttribute("name", "orderedQuantity"), new XAttribute("value", orderedQuantity))); // <parameter name="orderTypeKey" value="MKT" /> elementSourceOrder.Add(new XElement("parameter", new XAttribute("name", "orderTypeKey"), new XAttribute("value", "MKT"))); // <parameter name="securityKeyBySecurityId" value="ODP" /> elementSourceOrder.Add( new XElement("parameter", new XAttribute("name", "securityKeyBySecurityId"), new XAttribute("value", securityRow.EntityRow.ExternalId4))); // <parameter name="securityKeyBySettlementId" value="USD" /> elementSourceOrder.Add( new XElement("parameter", new XAttribute("name", "securityKeyBySettlementId"), new XAttribute("value", settlementCurrencyRow.EntityRow.ExternalId0))); // <parameter name="settlementDate" value="2012-05-09T17:27:56.2528086-04:00" /> elementSourceOrder.Add(new XElement("parameter", new XAttribute("name", "settlementDate"), new XAttribute("value", settlementDate))); // <parameter name="sideKey" value="SELL" /> elementSourceOrder.Add(new XElement("parameter", new XAttribute("name", "sideKey"), new XAttribute("value", sideRow.ExternalId0))); // <parameter name="statusKey" value="NEW" /> elementSourceOrder.Add(new XElement("parameter", new XAttribute("name", "statusKey"), new XAttribute("value", statusRow.ExternalId0))); // <parameter name="timeInForceKey" value="DAY" /> elementSourceOrder.Add( new XElement("parameter", new XAttribute("name", "timeInForceKey"), new XAttribute("value", timeInForceRow.ExternalId0))); // <parameter name="tradeDate" value="5/6/2012 5:27:56 PM" /> elementSourceOrder.Add(new XElement("parameter", new XAttribute("name", "tradeDate"), new XAttribute("value", tradeDate.ToString("G")))); // <parameter name="userKeyByCreatedUserId" value="DEV KAPOOR" /> elementSourceOrder.Add( new XElement("parameter", new XAttribute("name", "userKeyByCreatedUserId"), new XAttribute("value", userRow.EntityRow.ExternalId0))); // <parameter name="userKeyByModifiedUserId" value="DEV KAPOOR" /> elementSourceOrder.Add( new XElement("parameter", new XAttribute("name", "userKeyByModifiedUserId"), new XAttribute("value", userRow.EntityRow.ExternalId0))); // <parameter name="workingOrderKey" value="{bab88942-5c4e-440a-a352-c8e9b00fec12}" /> elementSourceOrder.Add( new XElement("parameter", new XAttribute("name", "workingOrderKey"), new XAttribute("value", workingOrderId.ToString("B")))); } }
internal AssetNetworkItem(AssetNetworkCollection owner, DataModel.EntityRow entityRow) { // The new instance is populated with data from the data model. this.Copy(owner, entityRow); }
/// <summary> /// Copies the information from the data model into the item. /// </summary> /// <param name="owner">The owner collection.</param> /// <param name="entityRow">The record in the data model that contains the information for this item.</param> protected void Copy(AssetNetworkCollection owner, DataModel.EntityRow entityRow) { // Validate the parameters if (owner == null) { throw new ArgumentNullException("owner"); } if (entityRow == null) { throw new ArgumentNullException("entityRow"); } // Copy the basic information out of the data model. These statements will also cause the NotifyPropertyChange event to fire. this.DateCreated = entityRow.CreatedTime; this.DateModified = entityRow.ModifiedTime; this.EntityId = entityRow.EntityId; this.Name = entityRow.Name; this.TypeDescription = entityRow.TypeRow.Description; this.TypeId = entityRow.TypeId; // Create properties from the metadata associated with this entity. foreach (DataModel.PropertyStoreRow propertyStoreRow in entityRow.GetPropertyStoreRows()) { // Copy the viewer property. if (propertyStoreRow.PropertyId == PropertyId.Viewer) { this.Viewer = new Uri(Encoding.Unicode.GetString(propertyStoreRow.Value as Byte[]), UriKind.RelativeOrAbsolute); } // Copy the data property. if (propertyStoreRow.PropertyId == PropertyId.Data) { this.Data = propertyStoreRow.Value as Byte[]; } } // This will disassemble the icon and give us the basic image sizes supported by the application framework. Dictionary <ImageSize, ImageSource> images = ImageHelper.DecodeIcon(Convert.FromBase64String(entityRow.ImageRow.Image)); this.SmallImageSource = images[ImageSize.Small]; this.MediumImageSource = images[ImageSize.Medium]; this.LargeImageSource = images[ImageSize.Large]; this.ExtraLargeImageSource = images[ImageSize.ExtraLarge]; // The next part of the copy operation involves recursing into the children and copying, moving or removing the items to reflect the current hierarchy. // This query is the meat of recursing into the hierarchy. This will create a sorted array of all the child items of this node. var children = from entityTreeItem in entityRow.GetEntityTreeRowsByFK_Entity_EntityTree_ParentId() where entityTreeItem.EntityRowByFK_Entity_EntityTree_ChildId.IsContainer == true orderby entityTreeItem.EntityRowByFK_Entity_EntityTree_ChildId.Name select entityTreeItem.EntityRowByFK_Entity_EntityTree_ChildId; DataModel.EntityRow[] childArray = children.ToArray <DataModel.EntityRow>(); // This list is part of a MVVM. Since this collection is designed to be bound to the user interface, it is important not to wipe it clean and rebuild // it each time something changes. The main idea of this algorithm is to find out what children are new, what children need to be updated and what // children need to be deleted without disturbing the other children. Int32 sourceIndex = 0; Int32 targetIndex = 0; while (targetIndex < this.Children.Count && sourceIndex < childArray.Length) { // The names of the node (within the scope of their parent node) is unique, just like a file system. If the list of new children doesn't match up // with the list provided by the data model, then we will insert, update or delete the list in order to reconcile the differences. AssetNetworkItem targetItem = this.Children[targetIndex] as AssetNetworkItem; DataModel.EntityRow childRow = childArray[sourceIndex]; // Items no longer in the data model are deleted from the list. Items that are already in the list have their contents copied (including children) // and new items are created (including their children) and added to the list. switch (String.Compare(targetItem.Name, childRow.Name, true, CultureInfo.CurrentCulture)) { case -1: // Remove children no longer in the data model. AssetNetworkItem removedItem = this.Children[targetIndex] as AssetNetworkItem; owner.RemoveDescendant(removedItem); this.Children.Remove(removedItem); break; case 0: // Copy items that are already in the list. targetItem.Copy(owner, childRow); sourceIndex++; targetIndex++; break; case 1: // Add new items (and their children) when they aren't in the list. AssetNetworkItem addedItem = new AssetNetworkItem(owner, childRow); owner.AddDescendant(addedItem); this.Children.Insert(targetIndex, addedItem); targetIndex++; sourceIndex++; break; } } // This covers the case where there were several children added to the list after the last item in the existing list. In this situation there is // nothing left to reconcile, just a bunch of new items to be concatenated to the current list of children. while (sourceIndex < childArray.Length) { AssetNetworkItem assetNetworkItem = new AssetNetworkItem(owner, childArray[sourceIndex]); owner.AddDescendant(assetNetworkItem); this.Children.Add(assetNetworkItem); sourceIndex++; } // The next part of the copy operation involves recursing into the children and copying, moving or removing the items to reflect the current hierarchy. // This query is the meat of recursing into the hierarchy. This will create a sorted array of all the child items of this node. var leaves = from entityTreeItem in entityRow.GetEntityTreeRowsByFK_Entity_EntityTree_ParentId() where entityTreeItem.EntityRowByFK_Entity_EntityTree_ChildId.IsContainer == false orderby entityTreeItem.EntityRowByFK_Entity_EntityTree_ChildId.Name select entityTreeItem.EntityRowByFK_Entity_EntityTree_ChildId; DataModel.EntityRow[] leavesArray = leaves.ToArray <DataModel.EntityRow>(); // This list is part of a MVVM. Since this collection is designed to be bound to the user interface, it is important not to wipe it clean and rebuild // it each time something changes. The main idea of this algorithm is to find out what leaves are new, what leaves need to be updated and what // leaves need to be deleted without disturbing the other leaves. Int32 sourceLeavesIndex = 0; Int32 targetLeavesIndex = 0; while (targetLeavesIndex < this.Leaves.Count && sourceLeavesIndex < leavesArray.Length) { // The names of the node (within the scope of their parent node) is unique, just like a file system. If the list of new leaves doesn't match up // with the list provided by the data model, then we will insert, update or delete the list in order to reconcile the differences. AssetNetworkItem targetItem = this.Leaves[targetLeavesIndex] as AssetNetworkItem; DataModel.EntityRow leafRow = leavesArray[sourceLeavesIndex]; // Items no longer in the data model are deleted from the list. Items that are already in the list have their contents copied (including leaves) // and new items are created (including their leaves) and added to the list. switch (String.Compare(targetItem.Name, leafRow.Name, true, CultureInfo.CurrentCulture)) { case -1: // Remove leaves no longer in the data model. AssetNetworkItem removedItem = this.Leaves[targetLeavesIndex] as AssetNetworkItem; owner.RemoveDescendant(removedItem); this.Leaves.Remove(removedItem); break; case 0: // Copy items that are already in the list. targetItem.Copy(owner, leafRow); sourceLeavesIndex++; targetLeavesIndex++; break; case 1: // Add new items (and their leaves) when they aren't in the list. AssetNetworkItem addedItem = new AssetNetworkItem(owner, leafRow); owner.AddDescendant(addedItem); this.Leaves.Insert(targetLeavesIndex, addedItem); targetLeavesIndex++; sourceLeavesIndex++; break; } } // This covers the case where there were several leaves added to the list after the last item in the existing list. In this situation there is // nothing left to reconcile, just a bunch of new items to be concatenated to the current list of leaves. while (sourceLeavesIndex < leavesArray.Length) { AssetNetworkItem assetNetworkItem = new AssetNetworkItem(owner, leavesArray[sourceLeavesIndex]); owner.AddDescendant(assetNetworkItem); this.Leaves.Add(assetNetworkItem); sourceLeavesIndex++; } }
/// <summary> /// Creates a data model entry for the given path element. /// </summary> /// <param name="parentItem"></param> /// <param name="path">The full file name of the document to be loaded.</param> /// <param name="externalDocument">The properties used to build the document.</param> static void CreateDocument(AssetNetworkItem parentItem, String path, DocumentProperty externalDocument) { // The general idea here is to create the data structure that will be passed to the server to create the documents. Once built, the same data is used // to modify the client side so it will look like the file was imported instantaneously. If the operation to add the document fails, then we will undo // the transaction but most of the time it will just look zippin' quick. This is list of metadata properties used to create the document. List <PropertyStoreInfo> propertyStoreList = new List <PropertyStoreInfo>(); // Each document requires an image so we can display an icon on the directory page. The icon used for the documents is acquired from the type // information (each type is associated with an icon). DataModel.TypeRow typeRow = DataModel.Type.TypeKey.Find(externalDocument.typeId); // IMPORTANT CONCEPT: In order to create the document on the client side, we need to have unique identifiers. These unique identifiers will be passed // to the server when it is time to create the document and all the records that go with it (metadata, entity tree, etc.). If the operation is not // successful, then we roll back this transaction and all these records will go away, but if the operation is successful, then we'll get back the // actual database record which will, by virtue of having the same identifiers created here, update these records with the actual server information // (most importantly, we'll get back a RowVersion and all the other server-side defaults). CreateDocumentInfo createDocumentInfo = new CreateDocumentInfo(); createDocumentInfo.EntityId = Guid.NewGuid(); createDocumentInfo.EntityTreeId = Guid.NewGuid(); createDocumentInfo.Name = Path.GetFileName(path); createDocumentInfo.ParentEntityId = parentItem.EntityId; createDocumentInfo.TypeId = typeRow.TypeId; // If a viewer has been specified for this file type, then create a metadata property for the viewer. if (!String.IsNullOrEmpty(externalDocument.ViewerUri)) { PropertyStoreInfo viewerPropertyInfo = new PropertyStoreInfo(); viewerPropertyInfo.PropertyStoreId = Guid.NewGuid(); viewerPropertyInfo.PropertyId = PropertyId.Viewer; viewerPropertyInfo.Value = Encoding.Unicode.GetBytes(externalDocument.ViewerUri); propertyStoreList.Add(viewerPropertyInfo); } // This will create a metadata property for the data that goes with an item. In this case, the data is the file contents. PropertyStoreInfo dataPropertyInfo = new PropertyStoreInfo(); dataPropertyInfo.PropertyId = PropertyId.Data; dataPropertyInfo.PropertyStoreId = Guid.NewGuid(); using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)) { MemoryStream memoryStream = new MemoryStream(); DirectoryPage.Copy(fileStream, memoryStream); Byte[] buffer = new Byte[memoryStream.Length]; Array.Copy(memoryStream.GetBuffer(), buffer, memoryStream.Length); dataPropertyInfo.Value = buffer; } propertyStoreList.Add(dataPropertyInfo); // Package the properties up in an array. createDocumentInfo.Properties = propertyStoreList.ToArray(); // At this point, we have enough data to create the document on the server. We could quit now and just send the message off to the server and wait for // the server to update the client with the newly created document. However, this involves a lag time which can be noticable on public systems. To // make it look like the operation was instantaneous, we're going to create the document on the client side. If the server accepts the web service // call, then all this data will be overwritten by the actual server version. If the operation fails, all this data will be rolled back. DataModel.EntityRow entityRow = DataModel.Entity.NewRow() as DataModel.EntityRow; entityRow.EntityId = createDocumentInfo.EntityId; entityRow.CreatedTime = DateTime.Now; entityRow.ImageId = typeRow.ImageId; entityRow.Name = createDocumentInfo.Name; entityRow.ModifiedTime = DateTime.Now; entityRow.RowVersion = 0; entityRow.IsContainer = false; entityRow.TypeId = createDocumentInfo.TypeId; DataModel.Entity.Rows.Add(entityRow); // This will create the client side version of all the properties associated with this document. foreach (PropertyStoreInfo propertyStoreInfo in createDocumentInfo.Properties) { DataModel.PropertyStoreRow viewerPropertyRow = DataModel.PropertyStore.NewRow() as DataModel.PropertyStoreRow; viewerPropertyRow.EntityId = createDocumentInfo.EntityId; viewerPropertyRow.PropertyId = propertyStoreInfo.PropertyId; viewerPropertyRow.PropertyStoreId = propertyStoreInfo.PropertyStoreId; viewerPropertyRow.RowVersion = 0; viewerPropertyRow.Value = propertyStoreInfo.Value; DataModel.PropertyStore.Rows.Add(viewerPropertyRow); } // Finally, we need a relation built between the parent container and this document. DataModel.EntityTreeRow entityTreeRow = DataModel.EntityTree.NewRow() as DataModel.EntityTreeRow; entityTreeRow.ParentId = parentItem.EntityId; entityTreeRow.ChildId = createDocumentInfo.EntityId; entityTreeRow.EntityTreeId = createDocumentInfo.EntityTreeId; entityTreeRow.RowVersion = 0; DataModel.EntityTree.Rows.Add(entityTreeRow); // The object will be added to the common data model from a background thread. ThreadPool.QueueUserWorkItem(DirectoryPage.CreateItemThread, createDocumentInfo); }
/// <summary> /// Creates orders in the simulated order book. /// </summary> private static void OrderHandler() { // This thread will create orders in the simulated order book from destination orders placed in the queue. This thread // is necessary due to the locking architecture that prevents accessing the data model during a commit operation (which // is where the event indicating a new or changed destination order originates). while (MarketSimulator.IsBrokerSimulatorThreadRunning) { // This thread will wait here until a destination order is available in the queue. DataModel.DestinationOrderRow destinationOrderRow = MarketSimulator.orderQueue.Dequeue(); // The code that adds an order to the simulated book must have exclusive access to the simulated data model. lock (MarketSimulator.syncRoot) { // The primary data model needs to be accessed also for ancillary data associated with the new order. using (TransactionScope transactionScope = new TransactionScope()) { try { // This context is used to keep track of the locks aquired for the ancillary data. DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction; // Lock the destination order. destinationOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(destinationOrderRow); // Lock the Security. DataModel.SecurityRow securityRow = destinationOrderRow.SecurityRowByFK_Security_DestinationOrder_SecurityId; securityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(securityRow); // The working order row must be locked to examine the flags DataModel.WorkingOrderRow workingOrderRow = destinationOrderRow.WorkingOrderRow; workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(workingOrderRow); // Lock the Entity. DataModel.EntityRow entityRow = securityRow.EntityRow; entityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(entityRow); // Calculate the quantity executed on this order (some orders are created with executions, such as crossed orders.) Decimal quantityExecuted = 0.0M; foreach (DataModel.ExecutionRow executionRow in destinationOrderRow.GetExecutionRows()) { executionRow.AcquireReaderLock(dataModelTransaction); dataModelTransaction.AddLock(executionRow); quantityExecuted += executionRow.ExecutionQuantity; } // The simulated order is added to the book. This collects all the information required to simulate the execution of this order. DataSetMarket.OrderRow orderRow = MarketSimulator.dataSetMarket.Order.NewOrderRow(); orderRow.BlotterId = destinationOrderRow.BlotterId; orderRow.DestinationOrderId = destinationOrderRow.DestinationOrderId; orderRow.OrderTypeCode = OrderTypeMap.FromId(destinationOrderRow.OrderTypeId); orderRow.QuantityOrdered = destinationOrderRow.OrderedQuantity; orderRow.QuantityExecuted = quantityExecuted; orderRow.SideCode = SideMap.FromId(destinationOrderRow.SideId); orderRow.Symbol = securityRow.Symbol; orderRow.TimeInForceCode = TimeInForceMap.FromId(destinationOrderRow.TimeInForceId); MarketSimulator.dataSetMarket.Order.AddOrderRow(orderRow); // Adding the first order to the simulated order book will enable the simulation thread to begin processing the orders. The order // simulation thread will continue until the book is filled. if (MarketSimulator.dataSetMarket.Order.Count == 1) { MarketSimulator.orderEvent.Set(); } } catch { } // The locks are no longer required. transactionScope.Complete(); } } } }
/// <summary> /// Simulation of brokers executing destination orders. /// </summary> private static void SimulateBroker() { // This will seed the random number generator. Random random = new Random(DateTime.Now.Millisecond); // An instance of the data model is required to update it. DataModel dataModel = new DataModel(); // This set of claims gives the current thread the authority to update the price table. List <Claim> listClaims = new List <Claim>(); listClaims.Add(new Claim(Teraque.ClaimTypes.Create, Teraque.Resources.Application, Rights.PossessProperty)); listClaims.Add(new Claim(Teraque.ClaimTypes.Update, Teraque.Resources.Application, Rights.PossessProperty)); listClaims.Add(new Claim(Teraque.ClaimTypes.Read, Teraque.Resources.Application, Rights.PossessProperty)); ClaimSet adminClaims = new DefaultClaimSet(null, listClaims); // Thread.CurrentPrincipal = new ClaimsPrincipal(new GenericIdentity("Broker Service"), adminClaims); // Every execution requires a user identifier (the user who created the execution) and the broker who executed the // trade. These values are hard coded at the moment but should be more intelligently assigned in the future. Guid userId = Guid.Empty; Guid brokerId = Guid.Empty; // Operating values are required for the simulation that come from the data model. using (TransactionScope transactionScope = new TransactionScope()) { // The middle tier context allows ADO operations to participate in the transaction. DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction; // The broker for all the executions is hard coded. DataModel.EntityRow brokerRow = DataModel.Entity.EntityKeyExternalId0.Find(new object[] { "ZODIAC SECURITIES" }); brokerRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(brokerRow); brokerId = brokerRow.EntityId; // The user who creates these executions is hard coded. DataModel.EntityRow userRow = DataModel.Entity.EntityKeyExternalId0.Find(new object[] { "ADMINISTRATOR" }); userRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(userRow); userId = userRow.EntityId; // The data model doesn't need to be locked any more. transactionScope.Complete(); } // This thread will run until an external thread sets this property to 'false'. while (MarketSimulator.IsBrokerSimulatorThreadRunning) { // Wait for orders to show up in the simulated order book. MarketSimulator.orderEvent.WaitOne(); // The simulator parameters need to be locked for each batch of simulated price changes. try { Monitor.Enter(MarketSimulator.syncRoot); // This will select a random price in the table and change the price by a random amount. if (MarketSimulator.dataSetMarket.Order.Rows.Count > 0) { // Select a random row from the order book. int orderIndex = random.Next(MarketSimulator.dataSetMarket.Order.Rows.Count); DataSetMarket.OrderRow orderRow = MarketSimulator.dataSetMarket.Order[orderIndex]; if (orderRow.IsBusy) { Thread.Sleep(0); continue; } orderRow.IsBusy = true; // This transaction is required to add the new execution. using (TransactionScope transactionScope = new TransactionScope()) { // The middle tier context allows ADO operations to participate in the transaction. DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction; // This will simulate a random selection of a price change is quoted. The 'quoteColumn' variable can be // used to reference the selected quote from any price row. Below, a random row will be selected for // the price change. int actionTypeIndex = random.Next(Enum.GetValues(typeof(ActionType)).Length); switch ((ActionType)Enum.GetValues(typeof(ActionType)).GetValue(actionTypeIndex)) { case ActionType.Execute: // This creates a random execution of the remaining shares on the order. DateTime dateTime = DateTime.Now; Guid blotterId = orderRow.BlotterId; Decimal quantityLeaves = orderRow.QuantityOrdered - orderRow.QuantityExecuted; Decimal quantityExecuted = quantityLeaves <= 100 ? quantityLeaves : Convert.ToDecimal(random.Next(1, Convert.ToInt32(quantityLeaves / 100.0M))) * 100.0M; DataSetMarket.PriceRow priceRow = MarketSimulator.dataSetMarket.Price.FindByConfigurationIdSymbol("US TICKER", orderRow.Symbol); Decimal executionPrice = 0.0M; if (priceRow != null) { executionPrice = orderRow.SideCode == SideCode.Buy || orderRow.SideCode == SideCode.BuyCover ? priceRow.BidPrice : priceRow.AskPrice; } Guid executionId = Guid.NewGuid(); Guid destinationOrderId = orderRow.DestinationOrderId; // When the order is completed, it is removed from the order book. When the order book is empty, the thread goes to sleep // until another thread puts something in the order queue. orderRow.QuantityExecuted += quantityExecuted; if (orderRow.QuantityOrdered == orderRow.QuantityExecuted) { MarketSimulator.dataSetMarket.Order.RemoveOrderRow(orderRow); if (MarketSimulator.dataSetMarket.Order.Count == 0) { MarketSimulator.orderEvent.Reset(); } } if (quantityExecuted > 0) { Monitor.Exit(MarketSimulator.syncRoot); dataModel.CreateExecution( 0.0M, blotterId, null, brokerId, 0.0M, dateTime, userId, destinationOrderId, StateMap.FromCode(StateCode.Acknowledged), executionId, executionPrice, quantityExecuted, null, null, false, dateTime, userId, null, null, null, null, StateMap.FromCode(StateCode.Acknowledged), 0.0M, 0.0M, 0.0M, 0.0M); Monitor.Enter(MarketSimulator.syncRoot); } break; } // This will commit the changes to the order book. transactionScope.Complete(); } // This allows another thread to work the order. orderRow.IsBusy = false; } } finally { Monitor.Exit(MarketSimulator.syncRoot); } // This allows other threads the chance to run. Thread.Sleep(0); } }
/// <summary> /// Updates prices using a United States ticker. /// </summary> /// <param name="symbolIndex">The index to use to find the symbol.</param> /// <param name="symbolKey">The symbol key.</param> /// <param name="currencyIndex">The index to use to find the currency.</param> /// <param name="currencyKey">The currency key.</param> /// <param name="quote">The quote used to update the price.</param> static void UpdatePriceBySymbolCurrency( DataModel.IEntityIndex symbolIndex, Object[] symbolKey, DataModel.IEntityIndex currencyIndex, Object[] currencyKey, Quote quote) { // The current transaction and the target data model is extracted from the thread. DataModelTransaction dataModelTransaction = DataModel.CurrentTransaction; TenantDataModel tenantDataSet = dataModelTransaction.TenantDataModel; // This will find the currency of the quote. DataModel.EntityRow currencyEntityRow = currencyIndex.Find(currencyKey); if (currencyEntityRow == null) { throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Entity", currencyKey)); } currencyEntityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(currencyEntityRow); if (currencyEntityRow.RowState == System.Data.DataRowState.Detached) { throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Entity", currencyKey)); } Guid currencyId = currencyEntityRow.EntityId; // This will find the security using the external identifier. DataModel.EntityRow securityEntityRow = symbolIndex.Find(symbolKey); if (securityEntityRow == null) { throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Entity", symbolKey)); } securityEntityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(securityEntityRow); if (securityEntityRow.RowState == System.Data.DataRowState.Detached) { throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Entity", symbolKey)); } Guid securityId = securityEntityRow.EntityId; // If the price record exists, then update it. If it doesn't exist then create it. Object[] priceKey = new Object[] { securityId, currencyId }; DataModel.PriceRow priceRow = DataModel.Price.PriceKey.Find(priceKey); if (priceRow == null) { tenantDataSet.CreatePrice( quote.AskPrice, quote.AskSize, quote.BidPrice, quote.BidSize, null, currencyId, null, quote.LastPrice, quote.LastSize, null, null, null, securityId, null, null); } else { priceRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(priceRow); if (priceRow.RowState == System.Data.DataRowState.Detached) { throw new FaultException <RecordNotFoundFault>(new RecordNotFoundFault("Price", priceKey)); } tenantDataSet.UpdatePrice( quote.AskPrice, quote.AskSize, quote.BidPrice, quote.BidSize, null, currencyId, null, quote.LastPrice, quote.LastSize, null, null, null, priceKey, priceRow.RowVersion, securityId, null, null); } }