About the PositionLimitRiskFirewallRule
The PositionLimitRiskFirewallRule class checks the current overall position of a particular order, or set of orders, matching the slices configured, and will reject that order if the position exceeds the limits provided in the input parameters. This risk firewall rule checks both the open and pending positions of matching orders.
Note: The difference between the client credit limit rule class and the position limit rule class is that the client credit limit rule class acts on the cash position, which is the cumulative value of all orders, where as the position limit rule class acts on the cumulative quantity position.
When adding a client credit limit rule class instance, set either individual minimum and maximum limits, or a symmetric limit. For example, 100 would set a positive limit to +100 and a negative limit to -100. Setting both symmetric and asymmetric configuration parameters for the same limit (warning or objection) results in an error, and the rule class instance is not added.
When you use the position limit rule class (or the client credit limit rule class) there are callbacks that you must add. Specifically, you must add at least one of each type of callback to the order receiver that will handle orders approved by these rule classes:
OrderReceiver.addAcceptedOrderCallback() OrderReceiver.addAcceptedAmendOrderCallback() OrderReceiver.addAcceptedCancelOrderCallback() Each callback must route or enqueue the order event (com.apama.oms.NewOrder, AmendOrder, CancelOrder) to the context that contains the position tracker that the application is using. This is required for the rule class to operate in the expected way.
The position limit rule class uses the CMF position service to calculate the overall position being tracked. This requires the application to have created both an open position tracker and a pending position tracker (see
Using default position trackers). You then pass the names of these position tracker instances into the rule class's
create() action. This allows the rule class to track the positions of orders from other areas of your application.
The CMF's position service requires the order management (com.apama.oms) events to be sent (either routed or enqueued) to the position tracker instances that you created. This means that your application code must ensure that OMS events are sent to the position trackers being used after the orders have been approved by the risk firewall. Failure to do so may result in the position being calculated incorrectly, and subsequently the rule class may approve orders that would breach the defined limits.
Caution: Where possible, the position trackers used should be in the same context as the risk firewall. This can help avoid a situation in which the position limit rule class approves orders that breach the defined limits. Such a situation might happen because the risk firewall can accept orders synchronously by means of callback actions, but the CMF position service is asynchronous. The position service listens for OMS events, and routes or enqueues position updates. Orders that are sent into the risk firewall should allow time for the correlator input queue to process the position update. The code sample at the end of this topic demonstrates what you must do to correctly implement the position limit rule class. Alternatively, you may implement a custom rule class implementation (see
Implementing custom risk firewall rule classes) that can operate safely in a synchronous architecture.
The com.apama.firewall.rules.PositionLimitRiskFirewallConsts object defines the constants for the configuration settings for the position limit rule class, as well as their default values. You should use these constants rather than specific values in order to ensure compatibility. The following table provides information about position limit rule class parameters.
Constant Name of Input Parameter | Description |
RULE_CLASS_NAME | The name of the rule class, which is "PositionLimitRiskFirewallRule". |
POSITION_LIMIT_PARAMETER | Symmetric objection limits. This is the symmetric quantity position up to which orders may accrue before the rule class rejects subsequent orders. |
POSITION_LIMIT_DEFAULT | Symmetric objection limits default, which is 0 by default. |
POSITION_WARNING_PARAMETER | Symmetric warning limits. This is the symmetric quantity position up to which orders may accrue before the rule class issues a warning for subsequent orders. |
POSITION_WARNING_DEFAULT | Symmetric warning limits default, which is 0 by default. |
MIN_POSITION_LIMIT_PARAMETER | Minimum objection limit. This is the minimum quantity position up to which orders may accrue before the rule class rejects subsequent orders. |
MIN_POSITION_LIMIT_DEFAULT | Minimum objection limit default. |
MIN_POSITION_WARNING_PARAMETER | Minimum warning limit. This is the minimum quantity position up to which orders may accrue before the rule class issues a warning for subsequent orders. |
MIN_POSITION_LIMIT_DEFAULT | Minimum warning limit default. |
MAX_POSITION_LIMIT_PARAMETER | Maximum objection limit. This is the maximum quantity position up to which orders may accrue before the rule class rejects subsequent orders. |
MAX_POSITION_LIMIT_DEFAULT | Maximum objection limit default value, which is 0 by default. |
MAX_POSITION_WARNING_PARAMETER | Maximum warning limit. This is the maximum quantity position up to which orders may accrue before the rule class issues a warning for subsequent orders. |
MAX_POSITION_WARNING_DEFAULT | Maximum warning limit default. |
CHECK_CANCEL_PARAMETER | Indicates whether this risk firewall rule instance should apply to CancelOrder objects. |
CHECK_CANCEL_DEFAULT | Default value for whether this risk firewall rule instance should apply to CancelOrder objects. By default, this is true, which means that cancel order requests are counted. |
SLICE_POSITION_SERVICEID | The set of service IDs that the position service will use for this instance if it needs to be different from those provided for the instance slice. The format is a stringified sequence<string>. This must be set when running in legacy mode. You may want to check against the position of orders that have been approved by a risk firewall in legacy mode. |
The following table provides information about position limit rule class state information parameters. The risk firewall uses these constants as part of the state returned in the com.apama.firewall.InstanceInfo object when you call the com.apama.firewall.RiskFirewall.getRulexxxInfo() set of actions.
Constant Name of Output Parameter | Description |
CURRENT_OPEN_POSITION | Integer value for the current open quantity position. |
CURRENT_PENDING_MIN_POSITION | Current minimum pending quantity position. |
CURRENT_PENDING_MAX_POSITION | Current maximum pending quantity position. |
CURRENT_TOTAL_MIN_POSITION | Current total minimum (open + minimum pending) quantity position for a rule instance. |
CURRENT_TOTAL_MAX_POSITION | Current total maximum (open + maximum pending) quantity position for a rule instance. |
The following code provides an example of using the position limit rule class.
using com.apama.position.tracker.OpenPositionTrackerFactory;
using com.apama.position.tracker.PendingPositionTrackerFactory;
using com.apama.firewall.RiskFirewallFactory;
using com.apama.firewall.RiskFirewall;
using com.apama.firewall.rules.PositionLimitRiskFirewallRule;
using com.apama.firewall.rules.PositionLimitRiskFirewallRuleConsts;
using com.apama.utils.Params;
using com.apama.oms.NewOrder;
using com.apama.oms.AmendOrder;
using com.apama.oms.CancelOrder;
using com.apama.oms.UpdateOrder;
monitor PositonLimitRuleExample {
context mainContext := context.current();
integer trackersCreated := 0;
action onload() {
// Create an instance of the open position tracker in the main context.
(new OpenPositionTrackerFactory).create(
mainContext, "MyOpenPositionTracker", cbCreatedTracker );
// Create an instance of the pending position tracker in the main context.
(new PendingPositionTrackerFactory).create(
mainContext, "MyPendingPositionTracker", cbCreatedTracker );
}
// This action is called after the position tracker instance
// has been created.
action cbCreatedTracker( boolean success, string msg ) {
log "Position Tracker has been created: "+success.toString()+" : "+msg;
trackersCreated := trackersCreated +1;
// After all trackers are created, start the test.
if( trackersCreated = 2 ) then {
startTest();
}
}
action startTest() {
// Create the risk firewall.
RiskFirewall rfw := (new RiskFirewallFactory).createCb(
mainContext, "MyFirewall", cbOnRiskFirewallCreated );
// Create and register the position limit rule class.
RuleClass ruleClass := (new PositionLimitRiskFirewallRule).create(
mainContext, "MyOpenPositionTracker", "MyPendingPositionTracker" );
rfw.registerRuleClass( ruleClass );
// Add some rule instances.
Params instanceConfig := new Params;
instanceConfig.addIntegerParam(
PositionLimitRiskFirewallRuleConsts.POSITION_LIMIT_PARAMETER, 20 );
instanceConfig.addIntegerParam(
PositionLimitRiskFirewallRuleConsts.POSITION_WARNING_PARAMETER, 15 );
integer instanceId := rfw.addRuleInstance(
ruleClass.getRuleClassName(), instanceConfig );
// Add handlers for all the approved OMS events from the risk firewall.
integer refId1 := rfw.getOrderReceiver().
addAcceptedOrderCallback( cbOnApprovedNewOrders );
integer refId2 := rfw.getOrderReceiver().
addAcceptedAmendCallback( cbOnApprovedAmendOrders );
integer refId3 := rfw.getOrderReceiver().
addAcceptedCancelCallback( cbOnApprovedCancelOrders );
// Add a callback for all OrderUpdate events from the risk firewall.
integer refId4 := rfw.getOrderSender().
addOrderUpdateCallback( cbOnOrderUpdates );
// The unlock will take effect immediately after the create() action.
rfw.unlock();
}
action cbOnRiskFirewallCreated( RiskFirewall rfw ) {
// Send a new order to the risk firewall.
rfw.getOrderSender().sendOrder( NewOrder("orderId_1","APMA.L",
9.0, "BUY", "LIMIT", 10,
"TargetService","","",
"TargetMarket","", "TraderA",
new dictionary<string,string> ) );
}
// Set up a callback handler for NewOrder events that the
// risk firewall has approved.
action cbOnApprovedNewOrders( NewOrder order ) {
// Send the NewOrder event to the context that the position trackers
// were created in.
route order;
// The application can now perform any other actions
// on this NewOrder event.
...
}
// Set up a callback handler for AmendOrder events that the
// risk firewall has approved.
action cbOnApprovedAmendOrders( AmendOrder amend ) {
// Send the AmendOrder event to the context that the position trackers
// were created in.
route amend;
// The application can now perform any other actions
// on this AmendOrder event.
...
}
// Set up a callback handler for CancelOrder events that the
// risk firewall has approved.
action cbOnApprovedCancelOrders( CancelOrder cancel ) {
// Send the CancelOrder event to the context that the position trackers
// were created in.
route cancel;
// The application can now perform any other actions
// on this CancelOrder event.
...
}
// This action will be called for any updates to the
// orders the risk firewall is handling.
action cbOnOrderUpdates( OrderUpdate update ) {
// Send the OrderUpdate event to the context that
// the position trackers were created in.
route update;
// The application can now perform any other actions
// on this OrderUpdate event.
...
}
}