I'm setting up a web.py server that can run on PythonAnywhere (uploaded there through GitHub) which listens to TradingView alerts on a URL (i.e. webhook) and posts orders (and sets stop-losses, etc.) on OANDA through their API
- A sell order isn't actually handled as a sell order, but as closing all open positions for the given
instrument
.- Note that if this signal is sent to OANDA when the markets are closed, it will be cancelled.
- A buy order is handled as a limit order with a Good-Til-Date 15 minutes in the future.
- That means that if it is sent when the markets are closed, it will most likely cancel (unless of course the markets open within those 15 minutes)
action
eitherbuy
orsell
ticker
a six-letter ticker without any separator (e.g.EURUSD
)close
the price you want to buy the instrument at (ignored for sells, see Things to consider)
units
the size of the position to open as a positive integer, in the currency of the instrument (e.g. in Euros for "EURUSD" or gold for "XAUEUR"). Defaults to500
trailing_stop_loss_percent
the percentage points belowclose
on which to start the trailing stop loss as a positive decimal. (E.g. to set it 5% below, enter0.05
.) Defaults to0.01
, i.e. 1%. See OANDA's documentation on trailing stops for more information.take_profit_percent
the percentage points aboveclose
to set the take profit at as a positive decimal. When the market reaches this point, the position is automatically closed. Defaults to0.06
, i.e. 6%trading_type
eitherlive
orpractice
, used to select the respective API key and account ID from yourcredentials.json
file. Defaults topractice
Any other parameters will not be handled, but are sent along. That means you will see them in your server logs.
Set up development environmentInstall and set up the web.py serverHave it listen to POST requests (test with Postman)Parse the parameters sent in the request to variables that can be sent along to OANDAAuthenticate with the OANDA APISend a test order to OANDA's paper traderAdd stop-losses and other risk management techniques to the OANDA callConnect the local web.py server with the OANDA API callTest if a request from Postman to the web.py server running locally reaches OANDA correctlyFind out why my limit order didn't go through in the beginning, but cancelled because it reaches the GTD. Maybe the market was closed? If that was the case the market won't move and there won't be any signals, right?Add some kind of verification so that only I can send orders through my webhookMove the server to PythonAnywhere so that TradingView can reach itSetup TradingView to send an alert to the server on PythonAnywhereHave the server return the result of a POST request for easier Postman debuggingHave the server translate what TradingView sends as{{ticker}}
and{{close}}
to what OANDA expects asinstrument
andprice
Makesize
optional with a default value set server-sideAdd different processing for buy and sell alertsFix the fact thatsize
works for XAUEUR, but not forEURUSD
Renameclose
toprice
in the alerts and everywhere else, in case someone wants to use a different priceAdd more alerts to TradingView once I have ironed out the JSON in the alertsAutomatically set price precision decimals and remove it as a parameter that can be messed withWait and see if one of those alerts from TradingView reaches OANDA correctlyAdd a mechanism that notifies me of every order (email, maybe?)git pull
the latest version to PythonAnywhere so that the email subject of sell orders is correct- Code cleanup, more object-oriented, maybe?
- Think of a way to handle alerts based on the last candle of the day, which will most likely be triggering buys/sells when the markets are closed. Don't forget weekends
pip install web.py
pip install requests
pip install sendgrid
, if you choose to use SendGrid's mail API to send order confirmations from PythonAnywhere to yourself- a
credentials.json
file containing a JSON like this:
{
"oanda_practice": {
"api_key": "<YOUR PRACTICE ACCOUNT API KEY>",
"account_id": "<YOUR PRACTICE ACCOUNT ID>"
},
"oanda_live": {
"api_key": "<YOUR LIVE ACCOUNT API KEY>",
"account_id": "<YOUR LIVE ACCOUNT ID>"
},
"sendgrid": {
"api_key": "<YOUR SENDGRID API KEY>",
"email_address": "<THE ADDRESS TO SEND FROM AND TO>"
}
}
The webhook is only available on /webhook/<ACCESS_TOKEN>
where <ACCESS_TOKEN>
is one of the items in the JSON list in access_tokens.json
. Create that file with the following contents:
[
"<ACCESS_TOKEN>"
]
Make sure to replace <ACCESS_TOKEN>
with an access token of your choice (e.g. have DuckDuckGo generate one for you)
Note that these are the only valid endpoints. The server won't tell you anything if you're trying to reach it somewhere else.
- Create an account, if you don't have one already
git clone
this repository through a Bash console. (I'll assume you clone into/home/<USERNAME>/tradingview-to-oanda
for the rest of the setup.)- Go to the "Files" tab and upload your
credentials.json
andaccess_tokens.json
to the repository's directory - Create a virtualenv (I named it "tradingview-to-oanda" and used Python 3.7, see the docs):
mkvirtualenv tradingview-to-oanda --python=/usr/bin/python3.7
- Open the "Web" tab and create a custom web app
- Set the following parameters:
- Source code = The directory you cloned the repository into
- Working directory = The same directory
- Virtualenv = The directory of the virtualenv you created, probably something like
/home/<USERNAME>/.virtualenvs/tradingview-to-oanda
- Then open the WSGI configuration file linked from the Web tab
- Comment the
HELLO WORLD
bit (⌘+/ works here) - Add this to the bottom:
# +++++++++++ web.py +++++++++++
# Added by me, based on https://help.pythonanywhere.com/pages/WebDotPyWSGIConfig
import sys
sys.path.append('/home/<USERNAME>/tradingview-to-oanda')
from server import app
application = app.wsgifunc()
- Save the file and go back to the Web tab
- Click the green Reload button
- Send a valid POST request to https://.pythonanywhere.com/webhook/<ACCESS_TOKEN> and see if it reaches OANDA
- Add an alert to whatever condition you want, for example a custom-built
study
- Check the Webhook URL box and paste the URL of your PythonAnywhere webhook including access token
- Make sure that the Message is a valid JSON containing at least:
{"action":"buy","ticker":"{{ticker}}","close":{{close}}}
Note:
- The server is built in such a way that what TradingView sends as
{{ticker}}
is translated to what OANDA expects asinstrument
andclose
is translated toprice
- If you want to sell every position you have for this ticker, use "
sell
" asaction