Starting strategies through API

For reference, this is some real code that I use to send bracket strategy orders:

const longBracket = {
  qty: orderQuantity,
  profitTarget: takeProfitThreshold,
  stopLoss: -(Math.ceil(takeProfitThreshold/5)),
  trailingStop: true
}

const shortBracket = {
  qty: orderQuantity,
  profitTarget: -takeProfitThreshold,
  stopLoss: (Math.ceil(takeProfitThreshold/5)),
   trailingStop: true
}

const bracket = decision === RobotAction.Buy ? longBracket : shortBracket

const orderData = {
   entryVersion: {
      orderQty: orderQuantity,
      orderType: 'Market',
   },
   brackets: [bracket]
}

const body = {
  accountId: parseInt(process.env.ID, 10),
  accountSpec: process.env.SPEC,
  symbol: contract.name,
  action: decision,
  orderStrategyTypeId: 2,
  params: JSON.stringify(orderData)
}

It chooses long or short brackets based on a simple algorithm (that part’s not important). takeProfitThreshold, orderQuantity, and contract are user-set parameters, bracket is either the shortBracket or longBracket object, decision is the "Buy" or "Sell" string. The process.env variables are just vars I captured globally via node, but one important thing to notice is that accountId must be an integer, and the params must be a string. body then is the final JSON body data that you’d need to send with the request.

Hi Alex,
How would I access the simulation account? Do I have to pay for this to try the API demo?
Thanks.

Hello @God,

To gain access to the API you must have a funded live account, and you must purchase the API Access add-on. Once you have a live account, you can follow this guide to get started. When the API is available for your user, you will have unlimited access to testing via simulation mode. To access the simulation mode API, use the demo.tradovateapi.com base URL. For live access, use the live.tradovateapi.com base URL.

Hope that helps.

Hi @Alexander ,

Same issue for me. Here is the payload and response:

POST /v1/orderStrategy/startorderstrategy HTTP/1.1
Authorization: Bearer XXXxxxXXX
Host: demo.tradovateapi.com
Content-Type: application/json
Content-Length: 336

{
    "accountId": 123456,
    "accountSpec": "DEMO123456",
    "symbol": "MESU1",
    "action": "Buy",
    "orderStrategyTypeId": 2,
    "params": "{\"entryVersion\":{\"orderQty\":1,\"orderType\":\"Market\"},\"brackets\":[{\"qty\":1,\"profitTarget\":2,\"stopLoss\":-3,\"trailingStop\":false}]}"
}
HTTP/1.1 404 Not Found
content-length: 0
Date: Fri, 20 Aug 2021 16:57:43 GMT
Via: 1.1 google
Alt-Svc: clear

Placing regular order works, so id and name are correct.

Thank you!

Hello @Savva,

I’m receiving a 200 response using your provided data and my own credentials. Ensure that you’re using your account entity ID and not your user ID. The account entity ID is shown from endpoints such as /account/list in the id field.

Yep, tried exactly those to no avail.

Hi Alexander, I am trying to McGyver an OSO order that triggers an OCO order.

I would like to go long NQZ1 at 14,700. When filled, I want to trigger an OCO order with a stop loss at 14,600 and a target of 14,800. Can you please help me figuring out what I am doing wrong and which approach is more efficient?:

'''
//Code Example 1:

const URL = 'demo.tradovateapi.com/v1'

const oco = {
    qty: 1,
    profitTarget: 100,
    stopLoss: -100,
    trailingStop: false
}

const params = {
    entryVersion: {
        orderQty: 1,
        orderType: "Limit",
        limitPrice: 14700,
    },
    brackets: oco
}

const body = {
    accountId: id,
    accountSpec: name,
    symbol: 'NQZ1',
    action: 'Buy',
    orderStrategyTypeId: 1,
    params: JSON.stringify(params)
}

const response = await fetch(URL + '/orderStrategy/startOrderStrategy', {
    method: 'POST',
    headers: {
        'Accept': 'application/json',
        'Authorization': `Bearer ${myAccessToken}`,
    },
    body: JSON.stringify(body)
})

const json = await response.json() 


//Code Example 2:

const URL = 'demo.tradovateapi.com/v1'

const limit = {
    action: 'Sell',
    orderType: 'Limit',
    price: 14800.00
}

const oco = {
    action: 'Sell',
    orderType: 'Stop',
    price: 14600.00,
    other: limit
}

const initial = {
    accountSpec: yourUserName,
    accountId: yourAcctId,
    action: "Buy",
    symbol: "NQZ1",
    orderQty: 1,
    orderType: "Limit",
    price: 14700.00,
    isAutomated: true
    brackets: oco
}

const response = await fetch(URL + '/order/placeorder', {
    method: 'POST',
    headers: {
        'Accept': 'application/json',
        'Authorization': `Bearer ${myAccessToken}`,
    },
    body: JSON.stringify(initial)
})

const json = await response.json() // { orderId: 0000000 }`

We actually have endpoints for OSOs and OCOs individually. You can find them in the official API docs here and here. Also make sure you use the full URL (including 'https://').

I have seen the documentation. My question is how would I combine the two in ONE order?

Oh I see, you basically just want to start a brackets strategy where placing your entry order will trigger your orders for take profit and stop loss, which each will cancel one another. What you were doing with 'startOrderStrategy' is probably your best bet for that, especially considering you can have more than one bracket entry. The interface will be easiest to use since it’s designed to do exactly that.

Were you also having a problem using one of these endpoints?

Edit:
P.S. I noticed you are using 1 for orderStrategyTypeId. Currently the value 2 is what you want, it refers to the built-in Brackets strategy which is the only currently supported order strategy type.

Thanks for getting back to me so quickly. Here is my situation. I have written a script on TradingView that triggers a webhook with the following data: entry limit, stop loss, target limit. The script only trades NQ. I am trying to find a simple solution, so I can format the alert in a way that the API can understand without jumping through too many hoops… Do you see a way to make this work?

Check out this other community post. It’s about using tradingview webhooks.

TL;DR - To trigger Tradovate API calls you’d need to build an intermediary back-end application to catch the webhooks you create with tradingview and then forward those messages to the Tradovate API with the correct headers.

Thanks, I am aware of this post. My question was simply how to place a limit buy order that triggers and OCO order with target and stop loss.

You can do this, but you would basically be re-implementing your own bracket-like strategy. You could do something like this:

  • subscribe to a user/syncRequest real-time websocket subscription and listen for the "props" event type.
  • Place your entry order via API request, whatever order type you need. Hold onto the orderId from the response.
  • Listen for a "props" type event with the entityType 'ExecutionReport'. You want to find an execution report with the same orderId you kept from the placeOrder response, and which has an ordStatus of type 'Complete' or 'Filled' to know when it’s time to trigger your next order.
  • Place your dependent OCO order based on the data from the related execution report.

But this is essentially what startOrderStrategy does for you already with less overhead, so I’d still advise trying to adapt your data to fit the startOrderStrategy mold.

Thank you for clarifying. This is very helpful.

I have one more question. Is Tradovate working on a solution to communicate with scripts built on TradingView (pine script)? The two companies already work together and I would assume that many people have written solutions in pine script that are just waiting to get deployed.

Hello All, I am trying to get a WebSocket strategy going, using the GitHub tutorial and sample rsiStrategyFP. I cannot for the life of me get the startorderstrategy to throw anything but 404. For comparison I used network monitor to grab a post from Tradovate:
orderStrategy/startorderstrategy
62

{“accountId”:123456,“symbol”:“MESZ1”,“orderStrategyTypeId”:2,“action”:“Sell”,“params”:"{“entryVersion”:{“orderId”:0,“orderQty”:1,“orderType”:“Market”,“timeInForce”:“GTC”},“brackets”:[{“qty”:1,“profitTarget”:-1.5,“stopLoss”:1,“trailingStop”:true}]}"} 1634681685.7525158

Compared to what I am sending:
orderStrategy/startorderstrategy
2

{“accountId”:123456,“symbol”:“MESZ1”,“orderStrategyTypeId”:2,“action”:“Sell”,“params”:"{“entryVersion”:{“orderId”:0,“orderQty”:1,“orderType”:“Market”,“timeInForce”:“GTC”},“brackets”:[{“qty”:1,“profitTarget”:-2,“stopLoss”:0.5,“trailingStop”:true}]}"}

I tried with and without accountSpec… Outside of a timestamp(?) at the end of the Tradovate post and values the parameters and order appear the same.
Thoughts? Suggestions?

Hello @Mr.Cage,

Can you please provide the the URL you’re using to connect the socket, and also the response that you’re getting from that request?

Hey @Alexander
The WebSocket is connected to ‘wss://demo.tradovateapi.com/v1/websocket’
The response from code block (below) is {s:404, i:2, d:’’}

let dispose = socket.request({
            url: 'orderStrategy/startOrderStrategy',
            body,
            callback: (id, r) => {
                if(id === r.i) {
                    console.log(JSON.stringify(r, null, 2))
                    dispose()
                }
            }
        })

@Alexander I’ve simplified the code a bit see below. I used the sample orderStrategy/startOrderStrategy example from the API documents and it failed with a 404… To prove that something works I kept the same acquire token code and used the sample /order/placeorder from the API documents. placeorder was successful. This is very curious.

import axios from 'axios';

interface AccessTokenResponse {
    errorText: string,
    accessToken: string,
    expirationTime: string,
    passwordExpirationTime: string,
    userStatus: string,
    userId: number,
    name:string,
    hasLive: boolean
}

const DEMO_URL = 'https://demo.tradovateapi.com/v1';

const connect = async (data) => {
        
        const response = await axios.post<AccessTokenResponse>(`${DEMO_URL}/auth/accesstokenrequest`, data);

        const bracket1 = {
            qty: 1,
            profitTarget: -30,
            stopLoss: 5.5,
            trailingStop: false
        }
        
        const bracket2 = {
            qty: 1,
            profitTarget: 40.75,
            stopLoss: -5.5,
            trailingStop: false
        }
        
        const params = {
            entryVersion: {
                orderQty: 1,
                orderType: "Stop",
                stopPrice: 4174.50,
            },
            brackets: [bracket1, bracket2]
        }

        const body = {
            accountId: 480000,
            accountSpec: 'DEMO240000',
            symbol: "MESZ1",
            action: "Sell",
            orderStrategyTypeId: 2,                        
            params: JSON.stringify(params)
        }

        const config = {            
            headers: {
                'Accept': 'application/json',
                'Authorization': `Bearer ${response.data.accessToken}`,
            }
        };

        const orderResponse = await axios
                    .post(`${DEMO_URL}/orderStrategy/startOrderStrategy`
                            , body
                            , config)
                    .catch(ex => {
                                    let r = ex.response;
                                });
};

connect({
    name:       "username",
    password:   "api_pwd",
    appId:      "Sample App",
    appVersion: "1.0",
    cid:        123,
    sec:        'secrets',
});

Hi,

would it be possible to share the json structure for ‘Limit’ ordertype in startorderstrategy