API
Finance in IT
Python
March 21

Notifications: action required for take profit / stop loss. In case your Broker doesn't support those orders

There is a Russian Broker — Tinkoff Bank. Now here is the problem: the broker doesn't support take profit and stop loss orders. At all. If you want to feel more convenient while trading, then you need some workaround for this situation, until Tinkoff Bank developers finally release those orders as the killer feature. In the article, I will show you my workaround.
update:2019-03-22, the Broker published platform 3.0.0 (a major update) in Google Play. The changelog features take profit/stop loss orders

Why did I decide to post the article here? I have an assumption, that Tinkoff Bank and his products are quite popular among IT crowd in Russia and probably some of them have very same need but don't have enough time or willingness to develop own temporary workaround. That's why I share my solution and solution's history.

Here I should say something about workarounds, which are provided by the broker. First, the broker has limit orders. The feature was released in February 2019 (and clients waited for it for almost two years). They feature working within one trade day. So, you need every trading day set them anew. One more flaw: you can't setup limits as you wish. There is some price range and you can't make a limit order with price out of the range. And this range is extremely narrow. On a volatile market, it makes you feel inconvenient. Finally, you can't create two multidirectional orders (in my case even the first limit order cause an instant crash of the broker mobile app and the broker's site doesn't provide this feature).

Second, the broker's mobile app provides a feature: you can subscribe to the asset's price changing. If threshold (absolute, in price, or relative, in percentage) is passed, you will get a notification. But again, you can't create two thresholds for the asset.

My workaround is quite simple:

  1. we do have thresholds for an asset. We calculate thresholds ourselves. If thresholds are passed, we make a manual action: sell or buying to get, as a result, profit or loss.
  2. we should get a data source, to get actual asset's price
  3. if the threshold is passed, we should send a notification.

While it looks simple enough, there are some details in my solution which I want to share and discuss.

1. While my securities portfolio had one asset, thresholds were defined in the script, and the stock search was made just plain, simple and not configurable at all. It was a bad solution, but fast and showed that idea was right. When I get new assets in the portfolio I made loading stock names, exchanges, thresholds from a file.

2. My first asset was a foreign stock, and the foreign stock could be bought or sold only in Saint-Petersburg exchange. My first rush was to parse the SPb exchange's site.

There is a volume descending sort, so it was easy to parse, because my asset always was on the first page. But March, 8 it was broken. I don't know why, but TSLA popped up on a 25th page. Their paginator uses JavaScript to download pages' data. There is a straight solution: download and parse all pages and find the asset. But it requires to much time to download and parse 25+ pages within each loop.

Instead of it, I decided to add as another data source the tradingview.com site. There is no need to parse a lot of pages to find your stock, because each asset has its own page, like this one:
www.tradingview.com/symbols/NASDAQ-TSLA

I assumed, that now my problems are gone, but I was wrong. The data on the pages load and update only with JS. So, Requests I used to download pages failed.

For this problem I know three different solutions:

PyQT, selenium (webdriver) and an extension Requests-HTML. Because I already have Requests module in my project, I decided to use Requests-HTML.

For my strong disappointment, it was not very stable, until I found some clues on StackOverFlow and such.

    session = HTMLSession()
    r = session.get(url)
    my = r.html.render(timeout=30)
    selector = 'span.tv-symbol-header-quote__value.tv-symbol-header-quote__value--large.js-symbol-last'
    price = r.html.find(selector)[0].text
    r.close()
    session.close()

Make attention to timeout, as well to both close() callings. Most examples are lacks these details, and it could arise some problems.

3. Now, when we have downloaded pages with JS data, parsed it and decided, whether we need to send a notification, there is only question: 'How do we send a notification?'. In my case, sms.ru offers a convenient API and 5 free SMS per day. Sign-up on an SMS gate. Create an API key. The key something like this:

24A41EA5-EEEE-CCCC-5555-094143C2EDDD

Sending SMS function from an earlier version of my solution:

def send_message(mymessage):
    sms_url = 'https://sms.ru/sms/send?api_id=key&to=number&msg=message&json=1'
    sms_url = sms_url.replace('key', mykey)
    sms_url = sms_url.replace('number', mynumber)
    sms_url = sms_url.replace('message', mymessage)
    sms_response = requests.get(sms_url)

It works well. I ran into the question: what if we already sent an SMS. The first version lacks any checks, so it sends an SMS within each loop. Again and again.

I added SMS counter, which the script checks before calling send_message.

    global sms_counter
    sms_counter = sms_counter + 1

Okay, we got it. But as new day arise, arise a new problem: how to flush SMS counter? Or, actually, when? I see three different ways: store the counter in DB (but my solution, for now, is stateless), parse date/time to flush the counter between trade days and restart the script in some point between two trading days. For now, I implemented the latest variant, but in the future, I may change it.

My solution now working, you may download it from GitHub.

For users, who don't know how to handle Python scripts, I offer packaged solution for Windows (courtesy of PyInstaller).

TODOs:

  1. parse date time to flush SMS counters instead of restarting the script;
  2. for now it's the stateless application, I want to add a DB;
  3. after #2, it would be nice to track a big increase or decrease asset's price (in relative to the closing price of the previous trade day);
  4. expand communications paths (Telegram, Viber, voice calls) and providers (for reliability purposes I want to add smsc.ru SMS-gate, because sms.ru stuck sometimes and doesn't return sms_response, though SMS is sent).
Did you find the article as useful?
66.6% Yes 2
33.3% No 1
Voted 3 users. Passed 3 users.
+6
470 3
Support the author
Comments 2
Similar posts