How to submit signals to C2
First, let's look at all the available fields and what they represent. The JSON body of the request requires a "Order" property containing some, and sometimes all of the following members:
Field Name | Required | Type | Description | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
StrategyId | Mandatory | integer | Your C2 StrategyId. You can find your trading strategy's ID number above the strategy's name on the main C2 system page. | ||||||||||||||||||||||||||||||||
OrderType | Mandatory | string | The type of signal. "1" = Market, "2" = Limit, "3" = Stop | ||||||||||||||||||||||||||||||||
Side | Mandatory | string | "1" = Buy, "2" = Sell | ||||||||||||||||||||||||||||||||
Side | Mandatory | string | "1" = Buy, "2" = Sell | ||||||||||||||||||||||||||||||||
OrderQuantity | Mandatory | integer | The order quantity | ||||||||||||||||||||||||||||||||
Limit | Optional | decimal | The Limit Price | ||||||||||||||||||||||||||||||||
Stop | Optional | decimal | The Stop Price | ||||||||||||||||||||||||||||||||
TIF | Mandatory | string | The time in force. "0" = Day, "1" = Good Till Cancel (GTC) | ||||||||||||||||||||||||||||||||
CancelReplaceSignalId | Optional | integer | Used to specify that this signal replaces another | ||||||||||||||||||||||||||||||||
ParentSignalId | Optional | integer | Used to specify that this signal is conditional (a child) on another | ||||||||||||||||||||||||||||||||
DoNotSyncToOpen | Optional | boolean | Used to indicate this order should not be synched in the brokerage account. Only applies to Opening non-market orders. See Do Not Follow To Open | ||||||||||||||||||||||||||||||||
StopLoss | Optional | decimal | Only available in NewStrategyOrder endpoint. The C2-formatted Price at which to place a exit order conditional on the parent | ||||||||||||||||||||||||||||||||
ProfitTarget | Optional | decimal | Only available in NewStrategyOrder endpoint. The C2-formatted Price at which to place a exit order conditional on the parent | ||||||||||||||||||||||||||||||||
DoNotCreateOCAGroup | Optional | boolean | Used to indicate that C2 should not create a OCA group with the ProfitTarget and StopLoss signals (if they are present above) | ||||||||||||||||||||||||||||||||
C2Symbol | Optional | JSON | The symbol in C2 format. Either C2Symbol or ExchangeSymbol must be present to indicate the symbol you want to trade.
| ||||||||||||||||||||||||||||||||
ExchangeSymbol | Optional | JSON | The symbol in the native exchange format. Either C2Symbol or ExchangeSymbol must be present to indicate the symbol you want to trade.
|
Simple Signal
Here is an example API request for a simple signal: It tells C2 to SELL SHORT 5 contracts of the June 2024 E-Mini S&P futures contract, at 4199.25 limit. The order is a DAY signal:
Request:
{ "Order": { "StrategyId": 89959688, "OrderType": "2", "Side": "2", "OrderQuantity": 5, "Limit": "4199.25", "TIF": "0", "C2Symbol": { "FullSymbol": "@ESM24", "SymbolType": "future" } } }
Response
{ "Results": [ { "SignalId": 144260505 } ], "ResponseStatus": { "ErrorCode": "200" } }
There are a few important things to notice about the C2 response. First, C2 tells me whether the API request I made triggered any sort of error, or if it was ok. In this case, the signal request was accepted, because ResponseStatus was 200. Notice also that C2 returned a SignalId number for me (144260505). This is useful because with this number I can refer to the signal in subsequent calls.
For example, I can cancel-replace the signal (i.e. change the limit price from 4199.25 to some other value), or cancel it completely. Variations on Signals You can submit market signals, limit signals, or stop signals. Here I submit a market signal to buy to open (BTO) 2 shares of IBM stock at the market. The following is a DAY signal:
Request:
{ "Order": { "StrategyId": 116881082, "OrderType": "1", "Side": "1", "OrderQuantity": 2, "TIF": "0", "ExchangeSymbol": { "Symbol": "IBM", "Currency": "USD", "SecurityType": "CS" } } }
Conditional Signals
Once you know a SignalId, it is easy to create a conditional signal. A conditional signal is an order that becomes valid only once the original (parent) signal is traded. To create a conditional signal, include a parameter: ParentSignalId. Like this:
Request:
{ "Order": { "StrategyId": 116881082, "OrderType": "2", "Side": "2", "OrderQuantity": 2, "Limit": 135, "TIF": "2", "ParentSignalId": 144260639, "ExchangeSymbol": { "Symbol": "IBM", "Currency": "USD", "SecurityType": "CS" } } }
Bracket Signals (Entry + Stop Loss + Profit Target)
It's a pain to create an entry signal as a "parent" then two separate conditional child signals: a stop-loss and a profit target. Why not do it all in one swoop? Like this:
Request:
{ "Order": { "StrategyId": 116881082, "OrderType": "1", "Side": "1", "OrderQuantity": 2, "TIF": "0", "ProfitTarget": 1.22, "StopLoss": 0.999, "C2Symbol": { "FullSymbol": "EURUSD", "SymbolType": "forex" } } }
Response:
{ "Results": [ { "SignalId": 144261816, "ProfitTargetSignalId": 144261818, "StopLossSignalId": 144261820, "ExitSignalsOCAGroupId": 144261817 } ], "ResponseStatus": { "ErrorCode": "200" } }
The stop loss and profit target are each assigned a separate SignalId by C2 (144261820 and 144261818 respectively), and thus can be referred to later. (For example, perhaps you will want to adjust your stop loss?)
You will also notice C2 created a One-Cancels-All (OCA) group (ExitSignalsOCAGroupId = 144261817). The profit target and stop loss are both part of the same OCA group. This means that when one is canceled, expired, or traded, the other is canceled.
If you don't want C2 to automatically group your bracket orders into an OCA group, just include the following parameter in your Order property: “DoNotCreateOCAGroup”: true
Cancel-and-Replace Signals
It is common to change a working signal's price. For instance, you might want to change the limit price of your profit target, which has not yet been reached; or the stop price of not-yet-triggered stop loss. Rather than requiring two steps to achieve this (by first, canceling a specific signal; and second, submitting a replacement order), you can achieve the same functionality in one step, by using the parameter called cancel-and-replace, or xreplace. Here we change the ProfitTarget limit order from the previous example:
Request:
{ "Order": { "StrategyId": 116881082, "OrderType": "2", "Side": "2", "OrderQuantity": 2, "OpenClose": "C", "TIF": "1", "Limit": 1.011, "CancelReplaceSignalId": 144261818, "C2Symbol": { "FullSymbol": "EURUSD", "SymbolType": "forex" } } }
Best Practices
- Choose you Symbology: You can use the native C2 symbols as you see them on the website ("C2Symbol"), or you can use exchange-native symbols ("ExchangeSymbol"). Just remember to only use one or the other (but not both at the same time).
- Don't send optional fields if you don't use them: There is no need to send optional fields unless you use them. e.g. don't send "CancelReplaceSignalId" unless you are actually doing a cancel-replace.
- Signal Modifications: You can only change the price of a signal, not its direction, duration or quantity.
- Logs: Always print logs of all requests and responses in a file (or database) so you can troubleshoot if needed.