Using the API to DIY your ETF savings-plan using cost averaging

blog photo
Joanne SnelInvalid Date

Or, in other words, setting up a ‘lazy’ automation for your periodically scheduled trades.

Hey! I’m Joanne and I’m part of 🍋 , a start-up that’s making the brokerage experience accessible to developers. We’re creating an API that allows you to participate in and interact with the stock market, for example by implementing an automated trading strategy or creating a dashboard that visualises your portfolio.

In this article, I’ll walk you through a simple dollar-cost averaging strategy with which you can automate your savings plan. Nothing fancy — just making your life easier 😉. And, to top it off, I’ll also show you how to set up a Telegram bot that notifies you whenever a trade is placed. Even if you’re unsure of what to build with the API, this article is bound to get your creative juices flowing. You can begin by signing up to,here.

Title Card for the Article "Using the API to implement a DCA strategy"

What is ‘dollar-cost averaging’?

If you’re already investing by placing, for example, 10% of your monthly salary into an ETF or mutual fund, you’re dollar-cost averaging (maybe we should call it euro-cost averaging). Many ETF savings plans follow a similar set-up. So, what does this strategy actually entail? Imagine you have a large sum of money, say €10.000, that you want to invest. If you’re dollar-cost averaging (DCA from now on), you’d choose to spread out your buy-ins, perhaps by investing €1.000 monthly for a period of 10 months. The opposite of DCA is lump-sum investing, which would entail investing the entirety of the sum at one point in time.

Why choose one over the other? Many investors choose DCA over lump-sum investing because it mitigates risk. You can expect the price of your chosen instrument to increase and decrease over these 10 months, but by consistently investing, you are ‘averaging out’ your cost basis (i.e. the average purchase price). Ideally, you’d just want to buy during downturns, but word has it, you can’t predict the market. 🤷‍♀ So, why would you ever do anything but DCA? The benefit of lump-sum investing is that your money begins to work for you right away. On the other hand, you run the danger of poorly timing the market, resulting in a too high buy-in price.

And why not use a platform that offers a pre-made savings plan? Simple: customisation and transparency. With a pre-made savings plan, you lack the flexibility to indicate trade execution date and time — and, very often, these happen at unfavourable times, which can cost you. Designing your savings strategy with the API means you have full control. You can avoid common buy-in dates, such as the beginning and end of the month. This way, you’ll have a price advantage over the others DCA-ing. You can choose what to trade, when your trades are executed, on which exchange to trade, how often to trade and for how long to trade. Also, you’re not limited to just ETFs — maybe you want to DCA Pinterest shares. It’s up to you.

Automating the DCA strategy 💵

Sure, you could sign into your brokerage account and manually place a trade weekly. But, you can also automate this process. I don’t know about you, but the latter sounds like much more fun (and future-you will probably thank you). Let’s jump right into the coding bit.

I’ve decided to use Python for this application, but feel free to use your preferred language — the logic remains the same.

Setting the Scene

Throughout this script, we will need to make GET and POST requests to the API. For that reason, we create a file with the class RequestHandler, which will, you guessed it, handle all of our requests. We create two separate GET functions because we need to make GET requests to both our Trading and Market Data APIs.

1import os
2import requests
3import json
4from dotenv import load_dotenv
5class RequestHandler:
6    def __init__(self):
7        load_dotenv()
8        self.headers = {'Authorization': 'Bearer ' + os.environ.get('API_KEY')}
9        self.url_trading: str = os.environ.get("BASE_URL_TRADING")
10        self.url_market: str = os.environ.get("BASE_URL_DATA")
11    def get_data_trading(self, endpoint: str):
12        response = requests.get(self.url_trading + endpoint, headers=self.headers)
13        return response.json()
14    def get_data_market(self, endpoint: str):
15        response = requests.get(self.url_market + endpoint, headers=self.headers)
16        return response.json()
17    def post_data(self, endpoint: str, data):
18        response = + endpoint, json.dumps(data), headers=self.headers)
19        return response.json()

Environment Variables

Notice how we use os.environ.get() and to access several environment variables? We need to define these variables either in a separate .env file, locally within your IDE or on whichever cloud application platform you’re using to host your script, such as Heroku.

These are the environment variables you’ll need to provide if you want to run this script:

1Environment Variable, Description
2API_KEY, Your API Key
3MIC, Market identifier code of Trading Venue
4BASE_URL_TRADING, The base URL of the Trading API
5BASE_URL_DARA, The base URL of the Market Data API


In theGitHub repositoryfor this project, you’ll notice that we’ve defined a directory called ‘models’ which includes one file: This is an object with specific properties and behaviours — which also directly reflects the structure of our API, you can read more about this in ourdocumentation

Order Class

An order is characterised by its ISIN, among other features — again, see our documentation for the full run-down. An order needs to be placedactivated and retrieved. These functionalities can be seen in the Order class as defined below.

1import os
2from dotenv import load_dotenv
3from helpers import RequestHandler
4class Order(RequestHandler):
5    def place_order(self, isin: str, expires_at: str, quantity: int, side: str):
6        load_dotenv()
7        order_details = {
8            "isin": isin,
9            "expires_at": expires_at,
10            "side": side,
11            "quantity": quantity,
12            "venue": os.getenv("MIC")
13        }
14        endpoint = f'orders/'
15        response = self.post_data(endpoint, order_details)
16        return response
17    def activate_order(self, order_id):
18        endpoint = f'orders/{order_id}/activate/'
19        response = self.post_data(endpoint, {})
20        return response
21    def get_order(self, order_id):
22        load_dotenv()
23        endpoint = f'orders/{order_id}/'
24        response = self.get_data_trading(endpoint)
25        return response

As you can see, these three functionalities can be realised through requests to our API. Therefore, by making Order a subclass of the RequestHandler class, we extend the functions that we defined in the latter class, allowing us to easily (and cleanly) interact with the API.

Putting it all together

After defining our helper functions, API objects and setting up our Telegram bot, it’s time to put all the pieces together.

As a first step, we define the buy_order() function, which places and activates a buy order for one share, specified by its ISIN. Our API is structured such that an order is first placed (status: inactive), then it must be activated (status: activated) and lastly it is executed (status: executed). The function continuously checks the status of the order, and when it is finally executed we use telegram-send to send a summary message about the trade.

To schedule the trades, we’re using theAdvanced Python Scheduler library. We call the buy_order() function every weekday at 10.30 CET.

1from models.Order import Order 
2from apscheduler.schedulers.blocking import BlockingScheduler
3from apscheduler.triggers.cron import CronTrigger
4from pytz import utc
5import os 
6import time
7import telegram_send  
8def buy_order():   
9 """    This method places and activates a buy order for 1 unit of the specified instrument every week.    :param isin: isin of the instrument you want to buy    """    try:        
10placed_order = Order().place_order(
11            isin="LU0274208692",            expires_at="p0d",            side="buy",               quantity=1,        )         
12             order_id = placed_order['results'].get('id')        
13             activated_order = Order().activate_order(order_id)        
14             print(activated_order)         
15             while True:            
16                      order_summary = Order().get_order(order_id)['results']            
17                      if order_summary.get('status') == 'executed':                
18                               print('executed')               
19                               break         
20             average_price = order_summary.get('executed_price')       
21             amount_bought = order_summary.get('executed_quantity')         telegram_send.send(messages=[f'Your automated trading strategy just purchased {amount_bought} share(s) '                                     f'at €{average_price/10000:,.2f} per share.'])     
22     except Exception as e:        
23         print(e) 
24if __name__ == '__main__':    
25scheduler = BlockingScheduler(timezone=utc)     
26scheduler.add_job(buy_order,                      trigger=CronTrigger(day_of_week="mon-fri",                                          hour=10,                                          minute=30,                                          timezone=utc),                      name="Perform DCA")    
27print('Press Ctrl+{0} to exit'.format('Break' if == 'nt' else 'C'))     
28try:        scheduler.start()    
29except (KeyboardInterrupt, SystemExit):       
30           pass

In the above code-snippet, I’ve decided to use an ETF that tracks worldwide developed equities. This way, we are further mitigating our risk. But, of course, this strategy can also be applied to individual stocks or different ETFs.

You might have noticed the line with the telegram_send(), wonder what that is all about? We still need to set up a Telegram bot to make sure the above code works. Let’s do that now.

Setting up a Telegram Bot 🤖

If you’re unfamiliar with Telegram, it’s a messaging software that supports bots. We’re going to use the Telegram API to configure a bot that automatically delivers a summary message to your smartphone once a trade has been executed.

Notification of DCA Bot (from Telegram)

The following section will show you how to set up Telegram notifications just like this one.

To begin, you need to register your new bot by sending /newbot to BotFather, further explanation can be found here. This yields a token, much like the token you are familiar with from the API.

To simplify the process, I’ll be using the telegram-send command-line tool, which can be installed from your terminal using pip as follows:

1$ pip install telegram-send
2$ telegram-send --configure

Your terminal will prompt you to insert your token, which connects your script to your bot. Then, after sending the given password to your new bot, you’ve successfully set up telegram-send. If this isn’t clear, full instructions can be found here.

We can then send messages using the following command:

1import telegram_send

In the following section, I will show you how to bring your Telegram bot to life (not literally).

GIF of Doctor Who Robot dancing

Note: many aspects of this script can be adjusted, such as the amount, frequency and type of instruments being traded. We suggest using it as a starting point and adding your own functionalities. The above code can be found in this GitHub repo.

Possible Extensions

Ideally, you want to set up your script and forget about it — in order for this to work, it needs to be constantly running, even when your computer is powered off. For this, we suggest hosting your script in the cloud, using a platform such as Heroku, which you can conveniently connect to GitHub. We’ve covered how to use Heroku in this article, but you can also follow this or this step-by-step guide.

You can depart from the DCA strategy slightly — for example, by incorporating daily market data. If the price of your instrument decreases by, say, 10%, you could program your Telegram bot to notify you. Then, by interacting with the bot, you can either choose to buy additional shares, or place your trade earlier than planned. For Telegram functionality beyond simply sending messages, I suggest looking into the python-telegram-bot wrapper. Maybe you also want to add a function that notifies you if more money needs to be added to your account.

By setting up your own automated dollar-cost averaging strategy, you are affording yourself more flexibility than when you sign up for a standard savings plan. For example, you could set the execution time to be more flexible. You can make sure the ETF is bought at the best time during the day and not when it is most convenient for the bank. In addition, you can include multiple instruments in one savings plan, removing the need to create a separate one for each ETF, as many saving plans require you to do. The possibilities are endless, so, how would you customise this strategy?

I hope this article gave you some inspiration to get started using the API. If you haven’t signed up to yet, you can do so here. If you’d like to talk to us: leave a comment, email us at or join our Slack community. We’d love to see you there!

Your lemoneer 🍋,


You might also be interested in

blog photo

Blog 38 - The market maker explained

Market Makers are crucial to provide liquidity to stock exchanges. In this blog post, we talk about what Market Makers do and why they are useful.

blog photo

5 (+1) YouTube channels for FinTech enthusiasts 

YouTube is a great way to learn about new things, including financial education or coding. Therefore, in this article we’d like to introduce you to 5 YouTube channels to level up your trading literacy.

blog photo

A short introduction to derivatives

In this article, we'd like to introduce you derivatives - they come up in finance and leave a lot of people scratching their heads, though it's totally worth it! Curious about hearing what's the difference between investing and trading, the coherence between finance and weather & why the Greeks even appear here? We'll discuss who’s using them, what they are and how they can be valued in the following.

Dive Deeper

Find more resources to get started easily

Check out our documentation to find out more about our API structure, different endpoints and specific use cases.


Join community

Join our Slack channel to actively participate in our community, ask questions to other users and stay up to date at all times.


Interested in building with us?

We are always looking for great additions to our team that help us build a brokerage infrastructure for the 21st century.

Need any help?
Ask a question in our CommunityAsk a question in our CommunityGet started with our DocumentationGet started with our DocumentationGet inspired on our BlogGet inspired on our Blog
© 2021Privacy PolicyImprint
All systems normal

As a tied agent under § 3 Sec. 2 WplG on the account and under the liability of DonauCapital Wertpapier GmbH, Passauer Str. 5, 94161 Ruderting (short: DonauCapital), GmbH offers you the receipt and transmission of orders for clients (§ 2 Sec. 2 Nr. 3 WpIG) of financial instruments according to § 3 Sec. 5 WpIG as well as brokerage of accounts.