├── README.md └── tradingview-IB-automated-trading-system.ipynb /README.md: -------------------------------------------------------------------------------- 1 | # End-to-End-TradingView-Alert-Transmission-and-Interactive-Brokers-API-Automated-Trading-System- 2 | This is a script (with omitted portions) that will conduct automated trading with alerts from TradingView.com and send them to an Interactive Brokers brokerage account 3 | 4 | 5 | Disclaimer: In concert with the requirements to implement the system, this system WILL EXECUTE LIVE TRADES ON INTERACTIVE BROKERS (IB). 6 | I have purposely left code snipits out of this script to ensure that persons that clone this repo WILL READ THE IB API DOCUMENTATION 7 | AND UNDERSTAND THEIR RISKS. Automated trading is a risk that YOU fully accept should market changes affect you adversely. 8 | 9 | 10 | Recognition: In developing this, I came across several sources (Obviously StackOverflow is one) but one source was crucial in the success of this development: @robswc. 11 | Please visit github.com/robswc/tradingview-webhook-bot for more details on how to the Python Flask and NGROK setup are done. 12 | 13 | 14 | # Assumptions 15 | 16 | In development of this system, there are several requirements that must be met in order to begin automated trading using this script. 17 | 18 | 1. Have a DEVELOPED an "ACCURATE" trading algorithm on TradingView.com. I will not be sharing my algos nor will this cover the development of them for yourself. 19 | TradingView.com has several examples and prebuilt algos available for learning. 20 | 21 | 2. Have a TradingView.com account, preferraly Premium in order to send alerts through a webhook 22 | 23 | 3. Have a funded IB account. 24 | 25 | 4. Have an NGROK account and install the ngrok package in your Python environment (KNOW HOW TO USE NGROK) 26 | 27 | 5. Downloaded and installed the IB API (ibapi) package in your Python environment. This will require GitBash or linking the Python environment to your 28 | command prompt (Windows). 29 | 30 | 6. Proper configuration of the Global Variables in you IB account to allow internal connections from 127.0.0.1. 31 | 32 | 7. Finally, the alerts on your model from TradingView must must have specific syntax in order for this Python script to properly utilize 33 | them and send orders. 34 | 35 | 36 | 37 | # The effective flow from alert to order sent to IB is as follows: 38 | 39 | TradingView alert (synced for webhook to NGROK tunnel) --> NGROK io tunnel --> Python Flask on port 5000 --> IB account for order delivery 40 | 41 | 42 | 43 | # Alerts 44 | 45 | Having the alerts from TradingView setup properly is approximately 50% of the battle. The "repianting" effect can cause severe issues 46 | with model accuracy, therefore, I utilize a multi-factor system to ensure that an ACTUAL order is complete on-time. This consists of 47 | developing an indicator on the model you develop and setting alerts for short and long positions from that indicator. I use this in 48 | tandem with the alerts on the model that TradingView.com has recently released. Additionally, in developing my model I made the model 49 | "lookback" and compare PREVIOUS TICKS in order to decide to go in on the CURRENT TICK. For example, I compare time[2] to time[3] instead 50 | of looking at indicators at time[0]. This ensures that an accurate alert is sent out. For high volumes of alerts, this may cause some 51 | positions to be missed but it will accurately get you in and out of whatever position you are in. 52 | 53 | 54 | 55 | # TradingView Alert Format 56 | 57 | The alert system from TradingView that I use consists of 2 items: 58 | 59 | 1. An initiator alert (this instantiates the global logic variables) 60 | 2. An alert order delivered by the model alert setting (See TradingView alerts on robswc's GitHub for more). 61 | 62 | The alert format inside of the model alert should be this EXACTLY: 63 | 64 | ${"ticker":"XX", "price":{{close}}}@{{strategy.order.comment}} {{strategy.order.action}}! {{strategy.order.contracts}} 65 | 66 | 67 | Note: For the initiator, use this for the Pine Script to setup the alert. 68 | This is straight from github.com/robswc/tradingview-webhook-bot: 69 | 70 | //@version=4 71 | study("Webhook Tester") 72 | alertcondition(true, title='Webhook Test') 73 | 74 | 75 | 76 | # Logic Programming 77 | 78 | Once the alert is recieved by the Python Flask on port 5000, there needs to be logic to determine the correct course of action. I have 79 | untilized logic gates that derive the information sent from the TradingView.com alert to determine whether the order is a buy, sell, 80 | or closing a position for either. Again, this is MY system and you may develop a better system to determine order composition. 81 | 82 | 83 | # Testing 84 | 85 | In order to test, I built out a test script that sent out posts to the NGROK webhook then made a new Python Flask script that had no 86 | logic gates and activated and sent orders once a post request was recieved. I then monitored my IB account (IN PAPER TRADING) to ensure 87 | that the order was received. 88 | 89 | 90 | 91 | 92 | I hope you find this helpful and Good Luck! 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /tradingview-IB-automated-trading-system.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "scrolled": true 8 | }, 9 | "outputs": [ 10 | { 11 | "name": "stdout", 12 | "output_type": "stream", 13 | "text": [ 14 | " * Serving Flask app \"__main__\" (lazy loading)\n", 15 | " * Environment: production\n", 16 | " WARNING: This is a development server. Do not use it in a production deployment.\n", 17 | " Use a production WSGI server instead.\n", 18 | " * Debug mode: off\n" 19 | ] 20 | }, 21 | { 22 | "name": "stderr", 23 | "output_type": "stream", 24 | "text": [ 25 | " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n", 26 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 27 | "127.0.0.1 - - [13/Jul/2020 23:47:18] \"POST /webhook HTTP/1.1\" 200 -\n", 28 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n", 29 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 30 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 31 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n", 32 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 33 | ] 34 | }, 35 | { 36 | "name": "stdout", 37 | "output_type": "stream", 38 | "text": [ 39 | "last order closed = 0\n", 40 | "b'${\"ticker\":\"ES\", \"price\":3000}@initiate!1' -1 -1 -1 0\n", 41 | "The next valid order id is: 584\n", 42 | "\n", 43 | "good connection to account...\n", 44 | "\n", 45 | "model initiated\n", 46 | "Still waiting for previous order to process...\n", 47 | "\n", 48 | " ONLY CLOSING OR RESET ORDERS ALLOWED \n", 49 | "the a count is: 0\n" 50 | ] 51 | }, 52 | { 53 | "name": "stderr", 54 | "output_type": "stream", 55 | "text": [ 56 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 57 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n", 58 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 59 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 60 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n", 61 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 62 | ] 63 | }, 64 | { 65 | "name": "stdout", 66 | "output_type": "stream", 67 | "text": [ 68 | "last order closed = 0\n", 69 | "b'${\"ticker\":\"ES\", \"price\":3151}@short_willr_1 sell! 1' -1 14 -1 -1\n", 70 | "The next valid order id is: 584\n", 71 | "\n", 72 | "good connection to account...\n", 73 | "\n", 74 | "NO ORDER IN QUEUE\n", 75 | "Order sent: LMT SELL on ES 202009 @ 3151\n", 76 | "\n", 77 | "#########################################\n", 78 | "###### YOU ARE IN A SELL POSITION ######\n", 79 | "#########################################\n", 80 | "OpenOrder. PermId: 459075941 ClientId: 123 OrderId: 584 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: SELL OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3151.0 AuxPrice: 0.0 Status: Submitted\n" 81 | ] 82 | }, 83 | { 84 | "name": "stderr", 85 | "output_type": "stream", 86 | "text": [ 87 | "127.0.0.1 - - [13/Jul/2020 23:49:03] \"POST /webhook HTTP/1.1\" 200 -\n" 88 | ] 89 | }, 90 | { 91 | "name": "stdout", 92 | "output_type": "stream", 93 | "text": [ 94 | "resetting a\n", 95 | "the a count is: 0\n" 96 | ] 97 | }, 98 | { 99 | "name": "stderr", 100 | "output_type": "stream", 101 | "text": [ 102 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 103 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n", 104 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 105 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 106 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n", 107 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 108 | ] 109 | }, 110 | { 111 | "name": "stdout", 112 | "output_type": "stream", 113 | "text": [ 114 | "CLOSING ORDER\n", 115 | "the a count is: 1\n", 116 | "last order closed = 0\n", 117 | "b'${\"ticker\":\"ES\", \"price\":3150}@long_willr_1 buy! 2' 13 -1 -1 -1\n", 118 | "The next valid order id is: 585\n", 119 | "\n", 120 | "good connection to account...\n", 121 | "\n", 122 | "NO ORDER IN QUEUE\n", 123 | "Order sent: LMT BUY on ES 202009 @ 3150\n", 124 | "\n", 125 | "#########################################\n", 126 | "###### YOU ARE IN A BUY POSITION ######\n", 127 | "#########################################\n", 128 | "OpenOrder. PermId: 459075942 ClientId: 123 OrderId: 585 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: BUY OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3150.0 AuxPrice: 0.0 Status: PreSubmitted\n", 129 | "OpenOrder. PermId: 459075942 ClientId: 123 OrderId: 585 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: BUY OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3150.0 AuxPrice: 0.0 Status: Filled\n", 130 | "OpenOrder. PermId: 459075942 ClientId: 123 OrderId: 585 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: BUY OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3150.0 AuxPrice: 0.0 Status: Filled\n" 131 | ] 132 | }, 133 | { 134 | "name": "stderr", 135 | "output_type": "stream", 136 | "text": [ 137 | "127.0.0.1 - - [13/Jul/2020 23:53:03] \"POST /webhook HTTP/1.1\" 200 -\n" 138 | ] 139 | }, 140 | { 141 | "name": "stdout", 142 | "output_type": "stream", 143 | "text": [ 144 | "resetting a\n", 145 | "the a count is: 0\n" 146 | ] 147 | }, 148 | { 149 | "name": "stderr", 150 | "output_type": "stream", 151 | "text": [ 152 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 153 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n", 154 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 155 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 156 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n", 157 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 158 | ] 159 | }, 160 | { 161 | "name": "stdout", 162 | "output_type": "stream", 163 | "text": [ 164 | "last order closed = 1\n", 165 | "b'${\"ticker\":\"ES\", \"price\":3150}@short_willr_1 sell! 1' -1 14 -1 -1\n", 166 | "The next valid order id is: 586\n", 167 | "CLOSING ORDER\n", 168 | "the a count is: \n", 169 | "good connection to account...\n", 170 | "\n", 171 | "NO ORDER IN QUEUE\n", 172 | "Order sent: LMT 1\n", 173 | "last order closed = 1\n", 174 | "b'${\"ticker\":\"ES\", \"price\":3150}@closing sell! 1' -1 8 0 -1\n", 175 | " SELL on ES 202009 @ 3150\n", 176 | "\n", 177 | "#########################################\n", 178 | "###### YOU ARE IN A SELL POSITION ######\n", 179 | "#########################################\n" 180 | ] 181 | }, 182 | { 183 | "name": "stderr", 184 | "output_type": "stream", 185 | "text": [ 186 | "127.0.0.1 - - [13/Jul/2020 23:57:01] \"POST /webhook HTTP/1.1\" 200 -\n" 187 | ] 188 | }, 189 | { 190 | "name": "stdout", 191 | "output_type": "stream", 192 | "text": [ 193 | "resetting a\n", 194 | "the a count is: 0\n" 195 | ] 196 | }, 197 | { 198 | "name": "stderr", 199 | "output_type": "stream", 200 | "text": [ 201 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 202 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n", 203 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 204 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n" 205 | ] 206 | }, 207 | { 208 | "name": "stdout", 209 | "output_type": "stream", 210 | "text": [ 211 | "CLOSING ORDER\n", 212 | "the a count is: 1\n", 213 | "last order closed = 0\n", 214 | "b'${\"ticker\":\"ES\", \"price\":3150}@long_willr_1 buy! 2' 13 -1 -1 -1\n", 215 | "The next valid order id is: 587\n", 216 | "\n", 217 | "good connection to account...\n", 218 | "\n", 219 | "NO ORDER IN QUEUE\n", 220 | "Order sent: LMT BUY on ES 202009 @ 3150\n", 221 | "\n", 222 | "#########################################\n", 223 | "###### YOU ARE IN A BUY POSITION ######\n", 224 | "#########################################\n" 225 | ] 226 | }, 227 | { 228 | "name": "stderr", 229 | "output_type": "stream", 230 | "text": [ 231 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n", 232 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 233 | ] 234 | }, 235 | { 236 | "name": "stdout", 237 | "output_type": "stream", 238 | "text": [ 239 | "OpenOrder. PermId: 459075944 ClientId: 123 OrderId: 587 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: BUY OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3150.0 AuxPrice: 0.0 Status: Submitted\n" 240 | ] 241 | }, 242 | { 243 | "name": "stderr", 244 | "output_type": "stream", 245 | "text": [ 246 | "127.0.0.1 - - [14/Jul/2020 00:11:03] \"POST /webhook HTTP/1.1\" 200 -\n" 247 | ] 248 | }, 249 | { 250 | "name": "stdout", 251 | "output_type": "stream", 252 | "text": [ 253 | "resetting a\n", 254 | "the a count is: 0\n" 255 | ] 256 | }, 257 | { 258 | "name": "stderr", 259 | "output_type": "stream", 260 | "text": [ 261 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 262 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n", 263 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 264 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 265 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n" 266 | ] 267 | }, 268 | { 269 | "name": "stdout", 270 | "output_type": "stream", 271 | "text": [ 272 | "last order closed = 1\n", 273 | "b'${\"ticker\":\"ES\", \"price\":3148.75}@short_willr_1 sell! 1' -1 14 -1 -1\n", 274 | "CLOSING ORDER\n", 275 | "the a count is: 1\n", 276 | "last order closed = 1\n", 277 | "b'${\"ticker\":\"ES\", \"price\":3148.75}@closing sell! 1' -1 8 0 -1\n", 278 | "The next valid order id is: 588\n", 279 | "\n", 280 | "good connection to account...\n", 281 | "\n", 282 | "NO ORDER IN QUEUE\n", 283 | "Order sent: LMT SELL on ES 202009 @ 3148.75" 284 | ] 285 | }, 286 | { 287 | "name": "stderr", 288 | "output_type": "stream", 289 | "text": [ 290 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 291 | ] 292 | }, 293 | { 294 | "name": "stdout", 295 | "output_type": "stream", 296 | "text": [ 297 | "\n", 298 | "\n", 299 | "#########################################\n", 300 | "###### YOU ARE IN A SELL POSITION ######\n", 301 | "#########################################\n" 302 | ] 303 | }, 304 | { 305 | "name": "stderr", 306 | "output_type": "stream", 307 | "text": [ 308 | "127.0.0.1 - - [14/Jul/2020 00:18:02] \"POST /webhook HTTP/1.1\" 200 -\n" 309 | ] 310 | }, 311 | { 312 | "name": "stdout", 313 | "output_type": "stream", 314 | "text": [ 315 | "resetting a\n", 316 | "the a count is: 0\n" 317 | ] 318 | }, 319 | { 320 | "name": "stderr", 321 | "output_type": "stream", 322 | "text": [ 323 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 324 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n" 325 | ] 326 | }, 327 | { 328 | "name": "stdout", 329 | "output_type": "stream", 330 | "text": [ 331 | "CLOSING ORDER\n", 332 | "the a count is: 1\n", 333 | "last order closed = 0\n", 334 | "b'${\"ticker\":\"ES\", \"price\":3148}@long_willr_1 buy! 2' 13 -1 -1 -1\n", 335 | "OpenOrder. PermId: 459075945 ClientId: 123 OrderId: 588 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: SELL OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3148.75 AuxPrice: 0.0 Status: PreSubmitted\n", 336 | "The next valid order id is: 589\n", 337 | "\n", 338 | "good connection to account...\n", 339 | "\n", 340 | "\n", 341 | "THIS IS THE CURRENT QUEUE ORDER STATUS: PreSubmitted\n", 342 | "\n", 343 | "THIS IS A HUNG ORDER\n", 344 | "hung order number: 2 the a count is: 1\n", 345 | "cancelling all orders\n", 346 | "Still waiting for previous order to process...\n" 347 | ] 348 | }, 349 | { 350 | "name": "stderr", 351 | "output_type": "stream", 352 | "text": [ 353 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 354 | "127.0.0.1 - - [14/Jul/2020 00:32:02] \"POST /webhook HTTP/1.1\" 200 -\n", 355 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 356 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n" 357 | ] 358 | }, 359 | { 360 | "name": "stdout", 361 | "output_type": "stream", 362 | "text": [ 363 | "\n", 364 | " ONLY CLOSING OR RESET ORDERS ALLOWED \n", 365 | "the a count is: 1\n" 366 | ] 367 | }, 368 | { 369 | "name": "stderr", 370 | "output_type": "stream", 371 | "text": [ 372 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n", 373 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 374 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n", 375 | "127.0.0.1 - - [14/Jul/2020 00:38:00] \"POST /webhook HTTP/1.1\" 200 -\n", 376 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n" 377 | ] 378 | }, 379 | { 380 | "name": "stdout", 381 | "output_type": "stream", 382 | "text": [ 383 | "CLOSING ORDER\n", 384 | "the a count is: 2\n", 385 | "last order closed = 0\n", 386 | "b'${\"ticker\":\"ES\", \"price\":3148.25}@closing sell! 1' -1 8 0 -1\n", 387 | "The next valid order id is: 589\n", 388 | "\n", 389 | "good connection to account...\n", 390 | "\n", 391 | "Waiting for reset order..\n", 392 | "Still waiting for previous order to process...\n", 393 | "\n", 394 | " ONLY CLOSING OR RESET ORDERS ALLOWED \n", 395 | "the a count is: 2\n" 396 | ] 397 | }, 398 | { 399 | "name": "stderr", 400 | "output_type": "stream", 401 | "text": [ 402 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 403 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n", 404 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n", 405 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 406 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n" 407 | ] 408 | }, 409 | { 410 | "name": "stdout", 411 | "output_type": "stream", 412 | "text": [ 413 | "last order closed = 0\n", 414 | "b'${\"ticker\":\"ES\", \"price\":3147}@long_willr_1 buy! 1' 13 -1 -1 -1\n", 415 | "The next valid order id is: 589\n", 416 | "\n", 417 | "good connection to account...\n", 418 | "\n", 419 | "NO ORDER IN QUEUE\n", 420 | "Order sent: LMT BUY on ES " 421 | ] 422 | }, 423 | { 424 | "name": "stderr", 425 | "output_type": "stream", 426 | "text": [ 427 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 428 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 429 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n", 430 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 431 | ] 432 | }, 433 | { 434 | "name": "stdout", 435 | "output_type": "stream", 436 | "text": [ 437 | " 202009 @ 3147\n", 438 | "\n", 439 | "#########################################\n", 440 | "###### YOU ARE IN A BUY POSITION ######\n", 441 | "#########################################\n", 442 | "OpenOrder. PermId: 459075947 ClientId: 123 OrderId: 589 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: BUY OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3147.0 AuxPrice: 0.0 Status: Submitted\n" 443 | ] 444 | }, 445 | { 446 | "name": "stderr", 447 | "output_type": "stream", 448 | "text": [ 449 | "127.0.0.1 - - [14/Jul/2020 00:43:05] \"POST /webhook HTTP/1.1\" 200 -\n" 450 | ] 451 | }, 452 | { 453 | "name": "stdout", 454 | "output_type": "stream", 455 | "text": [ 456 | "resetting a\n", 457 | "the a count is: 0\n" 458 | ] 459 | }, 460 | { 461 | "name": "stderr", 462 | "output_type": "stream", 463 | "text": [ 464 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 465 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n", 466 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 467 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n" 468 | ] 469 | }, 470 | { 471 | "name": "stdout", 472 | "output_type": "stream", 473 | "text": [ 474 | "CLOSING ORDER\n", 475 | "the a count is: 1\n", 476 | "last order closed = 0\n", 477 | "b'${\"ticker\":\"ES\", \"price\":3148.25}@closing sell! 1' -1 8 0 -1\n", 478 | "The next valid order id is: 590\n", 479 | "\n", 480 | "good connection to account...\n", 481 | "\n", 482 | "NO ORDER IN QUEUE\n", 483 | "Order sent: LMT SELL on ES 202009 @ 3148.25\n", 484 | "\n", 485 | "#########################################\n", 486 | "###### YOU ARE IN A SELL" 487 | ] 488 | }, 489 | { 490 | "name": "stderr", 491 | "output_type": "stream", 492 | "text": [ 493 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n", 494 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 495 | ] 496 | }, 497 | { 498 | "name": "stdout", 499 | "output_type": "stream", 500 | "text": [ 501 | " POSITION ######\n", 502 | "#########################################\n", 503 | "OpenOrder. PermId: 459075948 ClientId: 123 OrderId: 590 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: SELL OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3148.25 AuxPrice: 0.0 Status: Submitted\n" 504 | ] 505 | }, 506 | { 507 | "name": "stderr", 508 | "output_type": "stream", 509 | "text": [ 510 | "127.0.0.1 - - [14/Jul/2020 00:46:03] \"POST /webhook HTTP/1.1\" 200 -\n" 511 | ] 512 | }, 513 | { 514 | "name": "stdout", 515 | "output_type": "stream", 516 | "text": [ 517 | "resetting a\n", 518 | "the a count is: 0\n" 519 | ] 520 | }, 521 | { 522 | "name": "stderr", 523 | "output_type": "stream", 524 | "text": [ 525 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n" 526 | ] 527 | }, 528 | { 529 | "name": "stdout", 530 | "output_type": "stream", 531 | "text": [ 532 | "last order closed = 1\n", 533 | "b'${\"ticker\":\"ES\", \"price\":3150.75}@short_willr_1 sell! 1' -1 14 -1 -1\n", 534 | "The next valid order id is: 591\n", 535 | "\n", 536 | "good connection to account...\n", 537 | "\n", 538 | "NO ORDER IN QUEUE\n", 539 | "Order sent: " 540 | ] 541 | }, 542 | { 543 | "name": "stderr", 544 | "output_type": "stream", 545 | "text": [ 546 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n", 547 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 548 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 549 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n", 550 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 551 | ] 552 | }, 553 | { 554 | "name": "stdout", 555 | "output_type": "stream", 556 | "text": [ 557 | "LMT SELL on ES 202009 @ 3150.75\n", 558 | "\n", 559 | "#########################################\n", 560 | "###### YOU ARE IN A SELL POSITION ######\n", 561 | "#########################################\n", 562 | "OpenOrder. PermId: 459075949 ClientId: 123 OrderId: 591 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: SELL OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3150.75 AuxPrice: 0.0 Status: PreSubmitted\n", 563 | "OpenOrder. PermId: 459075949 ClientId: 123 OrderId: 591 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: SELL OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3150.75 AuxPrice: 0.0 Status: Filled\n", 564 | "OpenOrder. PermId: 459075949 ClientId: 123 OrderId: 591 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: SELL OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3150.75 AuxPrice: 0.0 Status: Filled\n" 565 | ] 566 | }, 567 | { 568 | "name": "stderr", 569 | "output_type": "stream", 570 | "text": [ 571 | "127.0.0.1 - - [14/Jul/2020 01:03:03] \"POST /webhook HTTP/1.1\" 200 -\n" 572 | ] 573 | }, 574 | { 575 | "name": "stdout", 576 | "output_type": "stream", 577 | "text": [ 578 | "resetting a\n", 579 | "the a count is: 0\n", 580 | "CLOSING ORDER\n", 581 | "the a count is: 1\n", 582 | "last order closed = 0\n", 583 | "b'${\"ticker\":\"ES\", \"price\":3151}@long_willr_1 buy! 2' 13 -1 -1 -1\n" 584 | ] 585 | }, 586 | { 587 | "name": "stderr", 588 | "output_type": "stream", 589 | "text": [ 590 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 591 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n", 592 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 593 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 594 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n" 595 | ] 596 | }, 597 | { 598 | "name": "stdout", 599 | "output_type": "stream", 600 | "text": [ 601 | "The next valid order id is: 592\n", 602 | "\n", 603 | "good connection to account...\n", 604 | "\n", 605 | "NO ORDER IN QUEUE\n", 606 | "Order sent: LMT BUY on ES 202009 @ 3151\n", 607 | "\n", 608 | "#########################################\n", 609 | "###### YOU ARE IN A BUY POSITION ######\n", 610 | "#########################################\n" 611 | ] 612 | }, 613 | { 614 | "name": "stderr", 615 | "output_type": "stream", 616 | "text": [ 617 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 618 | ] 619 | }, 620 | { 621 | "name": "stdout", 622 | "output_type": "stream", 623 | "text": [ 624 | "OpenOrder. PermId: 459075950 ClientId: 123 OrderId: 592 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: BUY OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3151.0 AuxPrice: 0.0 Status: PreSubmitted\n", 625 | "OpenOrder. PermId: 459075950 ClientId: 123 OrderId: 592 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: BUY OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3151.0 AuxPrice: 0.0 Status: Filled\n", 626 | "OpenOrder. PermId: 459075950 ClientId: 123 OrderId: 592 Account: DU2258209 Symbol: ES SecType: FUT Exchange: GLOBEX Action: BUY OrderType: LMT TotalQty: 1.0 CashQty: 0.0 LmtPrice: 3151.0 AuxPrice: 0.0 Status: Filled\n" 627 | ] 628 | }, 629 | { 630 | "name": "stderr", 631 | "output_type": "stream", 632 | "text": [ 633 | "127.0.0.1 - - [14/Jul/2020 01:08:02] \"POST /webhook HTTP/1.1\" 200 -\n" 634 | ] 635 | }, 636 | { 637 | "name": "stdout", 638 | "output_type": "stream", 639 | "text": [ 640 | "resetting a\n", 641 | "the a count is: 0\n" 642 | ] 643 | }, 644 | { 645 | "name": "stderr", 646 | "output_type": "stream", 647 | "text": [ 648 | "ERROR -1 2104 Market data farm connection is OK:usfarm.nj\n", 649 | "127.0.0.1 - - [14/Jul/2020 01:15:02] \"POST /webhook HTTP/1.1\" 200 -\n", 650 | "ERROR -1 2104 Market data farm connection is OK:usfuture\n" 651 | ] 652 | }, 653 | { 654 | "name": "stdout", 655 | "output_type": "stream", 656 | "text": [ 657 | "CLOSING ORDER\n", 658 | "the a count is: 1\n", 659 | "last order closed = 1\n", 660 | "b'${\"ticker\":\"ES\", \"price\":3150.5}@closing sell! 1' -1 8 0 -1\n", 661 | "The next valid order id is: 593\n", 662 | "\n", 663 | "good connection to account...\n", 664 | "\n", 665 | "Waiting for reset order..\n", 666 | "Still waiting for previous order to process...\n", 667 | "\n", 668 | " ONLY CLOSING OR RESET ORDERS ALLOWED \n", 669 | "the a count is: 1\n" 670 | ] 671 | }, 672 | { 673 | "name": "stderr", 674 | "output_type": "stream", 675 | "text": [ 676 | "ERROR -1 2104 Market data farm connection is OK:cashfarm\n", 677 | "ERROR -1 2104 Market data farm connection is OK:usfarm\n", 678 | "ERROR -1 2106 HMDS data farm connection is OK:ushmds\n", 679 | "ERROR -1 2158 Sec-def data farm connection is OK:secdefil\n" 680 | ] 681 | } 682 | ], 683 | "source": [ 684 | "from flask import Flask, request, abort\n", 685 | "\n", 686 | "import actions\n", 687 | "import auth\n", 688 | "import flask\n", 689 | "import pandas as pd\n", 690 | "import ast\n", 691 | "import json\n", 692 | "\n", 693 | "import threading\n", 694 | "import time\n", 695 | "\n", 696 | "from ibapi.client import EClient\n", 697 | "from ibapi.wrapper import EWrapper\n", 698 | "from ibapi.contract import Contract\n", 699 | "from ibapi.order import *\n", 700 | "\n", 701 | "\n", 702 | "# Create Flask object called app.\n", 703 | "app = Flask(__name__)\n", 704 | "\n", 705 | "\n", 706 | "# Create root to easily let us know its on/working.\n", 707 | "@app.route('/')\n", 708 | "def root():\n", 709 | " return 'online'\n", 710 | "\n", 711 | "\n", 712 | "@app.route('/webhook', methods=['POST'])\n", 713 | "def webhook():\n", 714 | " if request.method == 'POST':\n", 715 | " try:\n", 716 | " global a\n", 717 | " global order_status\n", 718 | " global hung_order\n", 719 | " global sent_order\n", 720 | " global last_order_closed\n", 721 | " \n", 722 | " the_list = ['PendingSubmit',\n", 723 | " 'PendingCancel',\n", 724 | " 'PreSubmitted', \n", 725 | " 'Submitted', \n", 726 | " 'ApiCancelled', \n", 727 | " 'ApiPending']\n", 728 | "\n", 729 | " tester = str(request.get_data())\n", 730 | " \n", 731 | " ### Creates a byte object instead of a dict from the literal eval \n", 732 | " ### This is an issue with TradingView's alert data types ###\n", 733 | " data = str(ast.literal_eval(str(tester)))\n", 734 | " \n", 735 | " \n", 736 | " ##############################################\n", 737 | " ### Parses out data from TradingView alert ###\n", 738 | " ##############################################\n", 739 | " \n", 740 | " sep = '@'\n", 741 | " literal = data.split(sep, 1)[0]\n", 742 | "\n", 743 | " sep_2 = '$'\n", 744 | " literal = literal.split(sep_2, 1)[1]\n", 745 | " literal = ast.literal_eval(str(literal))\n", 746 | "\n", 747 | " type_purchase = data.split(sep, 1)[1]\n", 748 | "\n", 749 | " sell = type_purchase.find('sell')\n", 750 | " buy = type_purchase.find('buy')\n", 751 | " closing = type_purchase.find('closing')\n", 752 | " initiator = type_purchase.find('initiate')\n", 753 | " closer = type_purchase.find('2')\n", 754 | " ##############################################\n", 755 | " \n", 756 | " \n", 757 | " \n", 758 | " ###################################################\n", 759 | " ### Initiates variables and allocates buy types###\n", 760 | " ###################################################\n", 761 | " \n", 762 | " if initiator == 0:\n", 763 | " a = 0\n", 764 | " order_status = 0\n", 765 | " hung_order = 0\n", 766 | " last_order_closed = 0\n", 767 | " \n", 768 | " if buy >= 0:\n", 769 | " literal['type'] = 'BUY'\n", 770 | " if (closing == 0) or (closer > 0):\n", 771 | " print('CLOSING ORDER')\n", 772 | " a = a+1\n", 773 | " print('the a count is: ', a)\n", 774 | "\n", 775 | " else: \n", 776 | " if sell > 0:\n", 777 | " literal['type'] = 'SELL'\n", 778 | " if (closing == 0) or (closer > 0):\n", 779 | " print('CLOSING ORDER') \n", 780 | " a = a+1\n", 781 | " print('the a count is: ', a)\n", 782 | " \n", 783 | " print('last order closed = ', last_order_closed)\n", 784 | " \n", 785 | " print(data, buy, sell, closing,initiator)\n", 786 | " data = literal\n", 787 | " ###################################################\n", 788 | " \n", 789 | " \n", 790 | " ##################################################\n", 791 | " ########## Interactive Brokers Functions #########\n", 792 | " ##################################################\n", 793 | "\n", 794 | " class IBapi(EWrapper, EClient):\n", 795 | " def __init__(self):\n", 796 | " EClient.__init__(self, self)\n", 797 | "\n", 798 | " def nextValidId(self, orderId: int):\n", 799 | " super().nextValidId(orderId)\n", 800 | " self.nextorderId = orderId\n", 801 | " print('The next valid order id is: ', self.nextorderId)\n", 802 | " \n", 803 | " def openOrder(self, orderId: int, contract: float, order: float,orderState: str):\n", 804 | " super().openOrder(orderId, contract, order, orderState)\n", 805 | " self.fill_status = orderState.status\n", 806 | " print(\"OpenOrder. PermId: \", order.permId, \"ClientId:\", order.clientId, \" OrderId:\", orderId, \n", 807 | " \"Account:\", order.account, \"Symbol:\", contract.symbol, \"SecType:\", contract.secType,\n", 808 | " \"Exchange:\", contract.exchange, \"Action:\", order.action, \"OrderType:\", order.orderType,\n", 809 | " \"TotalQty:\", order.totalQuantity, \"CashQty:\", order.cashQty, \n", 810 | " \"LmtPrice:\", order.lmtPrice, \"AuxPrice:\", order.auxPrice, \"Status:\", orderState.status)\n", 811 | " \n", 812 | " order.contract = contract\n", 813 | "\n", 814 | "\n", 815 | " def run_loop():\n", 816 | " app_ib.run()\n", 817 | "\n", 818 | " #Function to create FX Order contract\n", 819 | " def contract_order(symbol):\n", 820 | " contract = Contract()\n", 821 | " contract.symbol = symbol\n", 822 | " contract.secType = 'FUT'\n", 823 | " contract.exchange = 'GLOBEX'\n", 824 | " contract.currency = 'USD'\n", 825 | " contract.lastTradeDateOrContractMonth = '202009'\n", 826 | " return contract\n", 827 | " \n", 828 | " ##################################################\n", 829 | "\n", 830 | " \n", 831 | " ##################################################\n", 832 | " ########## Establishes Connections ###############\n", 833 | " ################################################## \n", 834 | " \n", 835 | " app_ib = IBapi()\n", 836 | " app_ib.connect('127.0.0.1', 7497, 123)\n", 837 | "\n", 838 | " app_ib.nextorderId = None\n", 839 | " app_ib.fill_status = None\n", 840 | "\n", 841 | " ### Start the socket in a thread ###\n", 842 | " \n", 843 | " api_thread = threading.Thread(target=run_loop, daemon=True)\n", 844 | " api_thread.start()\n", 845 | " \n", 846 | " ######################################################### \n", 847 | " ###### Check if the API is connected via orderid ########\n", 848 | " #########################################################\n", 849 | "\n", 850 | " while True:\n", 851 | " if isinstance(app_ib.nextorderId, int):\n", 852 | " print('')\n", 853 | " print('good connection to account...')\n", 854 | " print('')\n", 855 | " break\n", 856 | " \n", 857 | " \n", 858 | " ######################################################### \n", 859 | " ### Checks the order queue for any outstanding orders ###\n", 860 | " ### Begins Logic Looping ###\n", 861 | " #########################################################\n", 862 | " \n", 863 | " ### Checks queue for order status and hung orders in queue ###\n", 864 | " \n", 865 | " if (app_ib.fill_status in the_list)&(a<3):\n", 866 | " print('')\n", 867 | " print('THIS IS THE CURRENT QUEUE ORDER STATUS: ', app_ib.fill_status)\n", 868 | " print('')\n", 869 | " order_status = 0\n", 870 | " hung_order = hung_order + 1\n", 871 | " \n", 872 | " ### If a closing order, add 2 to a ###\n", 873 | " if closer < 0:\n", 874 | " if closing < 0:\n", 875 | " print('adding 2 to a')\n", 876 | " a = a + 2\n", 877 | " \n", 878 | " ### If the order is hung in the queue, then cancel the order coming in ###\n", 879 | " ### Note: This only applies to orders that are entering orders, not closing ###\n", 880 | " if (hung_order >= 1) & (hung_order <2):\n", 881 | " print('THIS IS A HUNG ORDER')\n", 882 | " hung_order = hung_order + 1\n", 883 | " print('hung order number: ', hung_order, 'the a count is: ', a)\n", 884 | " \n", 885 | " ### Cancels all orders if an entering order is hung ###\n", 886 | " if (hung_order >= 2) & (a <= 1):\n", 887 | " print('cancelling all orders')\n", 888 | " hung_order = 0\n", 889 | " \n", 890 | " app_ib.reqGlobalCancel()\n", 891 | " app_ib.disconnect()\n", 892 | " \n", 893 | " ### Sets the order status at 0 ###\n", 894 | " if initiator >= 0:\n", 895 | " order_status = 0\n", 896 | " print('model initiated')\n", 897 | " \n", 898 | " \n", 899 | " elif(app_ib.fill_status not in the_list):\n", 900 | " \n", 901 | " ### If the order is coming off of a hung status, only allows reset orders (non-closing orders) ###\n", 902 | " if (((closing >= 0)&(a>1)) | ((last_order_closed == 1) & ((closing >= 0)|(closer >=0)))):\n", 903 | " print('Waiting for reset order..')\n", 904 | " order_status = 0\n", 905 | " else:\n", 906 | " print('NO ORDER IN QUEUE')\n", 907 | " order_status = 1\n", 908 | "\n", 909 | " ### If a closing order is hung, cancels all incoming orders ###\n", 910 | " elif(hung_order >= 2) & (a > 1):\n", 911 | " if (app_ib.fill_status in the_list):\n", 912 | " print('cancelling current order #: ', app_ib.nextorderId)\n", 913 | " app_ib.cancelOrder(app_ib.nextorderId)\n", 914 | "\n", 915 | " ### If all gates are passed, allows closing orders through ###\n", 916 | " elif (closing >= 0) and (a < 1):\n", 917 | " print('')\n", 918 | " print('THIS IS A CLOSING SALE')\n", 919 | " order_status = 1\n", 920 | " print('The a count is :', a)\n", 921 | " print('second')\n", 922 | " \n", 923 | " \n", 924 | " ### Sends an order if all previous criteria are met ###\n", 925 | " if (order_status == 1)&(initiator < 0):\n", 926 | " \n", 927 | " #Creates order object\n", 928 | " order = Order()\n", 929 | " ticker = data['ticker']\n", 930 | " contract_expr = '202009' ########### This will change as contract expiration changes ###########\n", 931 | " order.action = data['type']\n", 932 | " order.totalQuantity = 1\n", 933 | " order.orderType = 'LMT'\n", 934 | " order.lmtPrice = str(data['price'])\n", 935 | "\n", 936 | " #Places order\n", 937 | " app_ib.placeOrder(app_ib.nextorderId, contract_order(ticker), order)\n", 938 | " app_ib.nextorderId += 1\n", 939 | " print('Order sent: ', order.orderType, '', order.action, '','on ', ticker, '', contract_expr, '@ ', order.lmtPrice)\n", 940 | " print('')\n", 941 | " print('#########################################')\n", 942 | " print('###### YOU ARE IN A', data['type'].upper(),'POSITION ######')\n", 943 | " print('#########################################')\n", 944 | " hung_order = 0\n", 945 | " time.sleep(1)\n", 946 | " \n", 947 | " \n", 948 | " print('resetting a')\n", 949 | " a = 0\n", 950 | " \n", 951 | " if (closing >= 0) |(closer > 0):\n", 952 | " last_order_closed = 1\n", 953 | " else: \n", 954 | " last_order_closed = 0\n", 955 | " \n", 956 | " print('the a count is: ', a)\n", 957 | " app_ib.disconnect()\n", 958 | "\n", 959 | " \n", 960 | " else: \n", 961 | " print('Still waiting for previous order to process...')\n", 962 | " print('')\n", 963 | " print(' ONLY CLOSING OR RESET ORDERS ALLOWED ')\n", 964 | " print('the a count is: ', a)\n", 965 | " app_ib.disconnect()\n", 966 | "\n", 967 | " ######################################### \n", 968 | " ######################################### \n", 969 | "\n", 970 | " except:\n", 971 | " traceback.print_exc(file=sys.stdout) \n", 972 | " return '', 200\n", 973 | " \n", 974 | "if __name__ == '__main__':\n", 975 | " app.run()\n", 976 | " " 977 | ] 978 | }, 979 | { 980 | "cell_type": "code", 981 | "execution_count": null, 982 | "metadata": {}, 983 | "outputs": [], 984 | "source": [ 985 | "## IB Order Status Strings\n", 986 | " * **PendingSubmit**: indicates that you have transmitted the order, but have not yet received confirmation that it has been accepted by the order destination. \n", 987 | " * **PendingCancel**: indicates that you have sent a request to cancel the order but have not yet received cancel confirmation from the order destination. At this point, your order is not confirmed canceled. It is not guaranteed that the cancellation will be successful. \n", 988 | " * **PreSubmitted**: indicates that a simulated order type has been accepted by the IB system and that this order has yet to be elected. The order is held in the IB system until the election criteria are met. At that time the order is transmitted to the order destination as specified . \n", 989 | " * **Submitted**: indicates that your order has been accepted by the system. \n", 990 | " * **ApiCancelled**: after an order has been submitted and before it has been acknowledged, an API client client can request its cancelation, producing this state. \n", 991 | " * **ApiPending**: undocumented; heard it exists from the e-mail group.\n", 992 | " * **Cancelled**: indicates that the balance of your order has been confirmed canceled by the IB system. This could occur unexpectedly when IB or the destination has rejected your order. \n", 993 | " * **Filled**: indicates that the order has been completely filled. Market orders executions will not always trigger a Filled status. \n", 994 | " * **Inactive**: indicates that the order was received by the system but is no longer active because it was rejected or canceled.\n" 995 | ] 996 | } 997 | ], 998 | "metadata": { 999 | "kernelspec": { 1000 | "display_name": "Python 3", 1001 | "language": "python", 1002 | "name": "python3" 1003 | }, 1004 | "language_info": { 1005 | "codemirror_mode": { 1006 | "name": "ipython", 1007 | "version": 3 1008 | }, 1009 | "file_extension": ".py", 1010 | "mimetype": "text/x-python", 1011 | "name": "python", 1012 | "nbconvert_exporter": "python", 1013 | "pygments_lexer": "ipython3", 1014 | "version": "3.7.4" 1015 | } 1016 | }, 1017 | "nbformat": 4, 1018 | "nbformat_minor": 2 1019 | } 1020 | --------------------------------------------------------------------------------