private static void ValidateAccount(Account account) { // Calculate the total market value of the given account and the sector market value for the telecommunications // sector. Note how simple, object oriented operations (e.g. "GetMarketValue", "GetPositions") make a very complicated // tasks on the account data appear relatively easy to program. decimal totalMarketValue = account.GetMarketValue(); decimal sectorMarketValue = account.GetMarketValue(telecomServices); // If the sector market value of the industry is greater than the predefined limit, a violation will be generated for // every security in that sector that belongs to this account. Conversely, If the industry concentration is below the // limit, any existing violations will be cleared. if (sectorMarketValue / totalMarketValue >= sectorLimit) { foreach (Position position in account.GetPositions(TelecomConcentration.telecomServices)) { Violation violation = Violation.Find(TelecomConcentration.restriction, position); if (violation == null) { Violation.Add(TelecomConcentration.restriction, position, position.Security.Symbol, position.Account.Name, sectorLimit, TelecomConcentration.telecomServices.Name); } } } else { foreach (Violation violation in Violation.Find(restriction, account)) { violation.Remove(); } } }
/// <summary> /// Evaluates a given position for a restricted security. /// </summary> /// <param name="action">Indicates whether the position is being added, modified or deleted.</param> /// <param name="position">An account, security and position type (long or short) combination.</param> private static void EndMerge(object sender, EventArgs eventArgs) { foreach (Position position in AlphaListRule.updatePositionTable) { Violation violation = Violation.Find(restriction, position); if (position.GetQuantity() == 0.0M) { if (violation != null) { violation.Remove(); } } else { if (violation == null) { Violation.Add(restriction, position, position.Security.Symbol, position.Account.Name); } } } }
/// <summary> /// Install an event driven compliance check and initialize the violations table. /// </summary> static AlphaListRule() { // This will create a table of positions for every combination of a restricted securities in a restricted account. // This is just one example of how a set of restricted positions could be created. AlphaListRule.alphaPositionTable = new PositionTable(new AlphaAccountList(), new AlphaSecurityList()); AlphaListRule.updatePositionTable = new PositionTable(); // This a simple "Restricted Security" compliance check. If a position exists or is created on the predefined account // and security combination, then a 'Violation' record will be created. Conversely, if those conditions are removed, // the corresponding violation will be deleted. The first parameter to opening up a 'Restriction' is the user-defined // name, which must be unique for this rule. The restriction can specify a severity level and how many overrides are // required to allow it to trade. Also, a message with replacable parameters can be specified here. When a violation // is created, this message and the optional data items are combined to create a specific message for the violation. In // this example, the ticker symbol and account name will be filled when the violation is created. AlphaListRule.restriction = Restriction.Find("ALPHALIST"); if (AlphaListRule.restriction == null) { AlphaListRule.restriction = new Restriction("ALPHALIST", Severity.High, Approval.Officer, "Security '{0}' is restricted from account {1}."); } // The violations need to be synchronized with the current state of the data model when this compliance check is first // installed . That is, since the programming model is event driven, the state of the violations has to be initialized // for the incremental rule checking to work. This step will remove any violations that are no longer valid. foreach (Violation violation in restriction.GetViolations()) { if (violation.Position.GetQuantity() == 0.0M) { violation.Remove(); } } // This will complete the task of synchronizing the data model for the compliance rule. If a non-zero position is // found in the list of restricted securities and accounts, a violation on that position will be generated. foreach (Position position in AlphaListRule.alphaPositionTable) { // Create a position object based on the account, security and long or short position type. Any quantity found for // that position will trigger a violation. Note that if a violation already exists for this restriction and // position combination, the description of the violation will be overwritten, but the record will be otherwise // unchanged. if (position.GetQuantity() != 0.0M) { Violation violation = Violation.Find(restriction, position); if (violation == null) { Violation.Add(restriction, position, position.Security.Symbol, position.Account.Name); } } } // Flush the command buffer. CommandBatch.Flush(); // This compliance check is event driven. When an event -- such as adding or deleting an order -- changes the state of // the data model, these tests will be called to insure that the new state doesn't violate this compliance rule. In // the case of a simple list rule, the new position will be tested to see if adding or deleting a position results in a // violation. These statements install the event handlers for tax lots, proposed orders, orders and allocations. For // example, the method 'TaxLotHandler' will be called when the tax lot table changes. MarketData.BeginMerge += new EventHandler(BeginMerge); TaxLot.Changed += new TaxLotEvent(TaxLotHandler); ProposedOrder.Changed += new ProposedOrderEvent(ProposedOrderHandler); Order.Changed += new OrderEvent(OrderHandler); Allocation.Changed += new AllocationEvent(AllocationHandler); MarketData.EndMerge += new EventHandler(EndMerge); }