Trading Venues at lemon.markets — the what, why and how


blog photo
Joanne SnelJuly 15, 2021
Product


Hi! My name is Joanne, and I am a recent addition to the (steadily growing) lemon.markets team. We are building an API that allows developers to create their own brokerage experience at the stock market. I would like to introduce you to some of the functionalities of our API. This week’s topic: Trading Venues. Think of a trading venue as a stock exchange or other type of exchange where instruments are traded, for example, theLondon Stock Exchange (LSE).

At lemon.markets, we created a number of endpoints concerned with addressing specific trading venues. In this blog post, I will walk you through these endpoints and explain why you might want to use them. I will also show you how they can be used to set up automated emails that notify you when the market is closed.

Title Card for the Article "Trading Venues at lemon.markets"

Trading Venues is a new feature we decided to incorporate into our restructured API because we think it adds a powerful functionality. On our path to create a transparent 21st century broker, we think it is important that our users know (and have the option to decide) which trading venue they are placing their orders at. But before we discuss trading venues in a specific lemon.markets context, let us first dive into a bit of background information here:

At the time of writing this blog post (July 2021), there are 21 major stock exchanges in the world that have a market capitalisation of over $1 trillion US dollars, you might have heard of them referred to as the “$1 Trillion Club”. And there are also plenty of stock exchanges that have a smaller reach; have you heard of the Maldives Stock Exchange (MSE) that has just 10 listings? As you can see, the options (get it? 😉) for trading are endless.

Depending on what you are trying to do/build, it can be helpful to know the ins and outs of the stock exchange you are operating on to ensure that your trades go according to plan. By talking to our users, we noticed that there may be different needs and preferences regarding different trading venues, so we wanted to lay a flexible foundation for our API that allows us to integrate additional trading venues in the future.

A small Trading Venue Repository

We built a small project to demonstrate a number of use cases regarding trading venues. You can find the GitHub repository here 👩🏿‍💻👨‍💻👩🏼‍💻🧑🏿‍💻.

Setting the Foundation

Initially, we need to define a few helper functions. As we want to send emails at some point during our script, we define a class “EmailSenderSendgrid”. Surprisingly, we use Sendgrid, which makes API-based email sending super easy. In order to use our repo, you need to have a Sendgrid Account and pass your Sendgrid API Key as an environment variable. If you do not have an account, yet: sign up here.

Next, we define functions for get, put and post requests to be able to use them throughout the script.

Additionally, we need to define a number of environment variables to be able to use the script:

  • API_KEY = “Your lemon.markets API key”
  • BASE_URL_TRADING = “The base URL of our Paper Money API”
  • BASE_URL_DATA = "The base URL of our Market Data API"
  • MIC = “Market Identifier Code of Trading Venue”
  • SENDGRID_API_KEY = “Your Sendgrid API Key”
  • EMAIL_FROM = “Email you want to send emails from”
  • EMAIL_TO= “Email you want to send emails to”
1import os 
2import smtplib from email.mime.multipart 
3import MIMEMultipart from email.mime.text 
4import MIMEText 
5import requests
6import json from dotenv 
7import load_dotenv from sendgrid 
8import SendGridAPIClient from sendgrid.helpers.mail 
9import Mail   
10class EmailSenderSendgrid:     
11     def __init__(self, mail_text: str, mail_subject: str):        
12             load_dotenv()         
13             message = Mail( from_email=os.environ.get('EMAIL_FROM'),             
14                                           to_emails=os.environ.get('EMAIL_TO'),             
15                                           subject=mail_subject,            
16                                           html_content=mail_text)        
17      try:   
18          sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))             
19         response = sg.send(message)             
20         print(response.status_code)             
21         print('Email successfully delivered')         
22      except Exception as e:             
23         print(e)   
24class RequestHandler:     
25       load_dotenv()     
26       url_data: str = os.environ.get("BASE_URL_DATA")     
27       url_trading: str = os.environ.get("BASE_URL_TRADING")      
28       def get_data_data(self, endpoint: str):         
29              """         
30             :param endpoint: {str} only append the endpoint to the base url         
31             :return:        
32              """        
33            response = requests.get(self.url_data + endpoint,                                 
34                                                       headers={                                     
35                                                              "Authorization": "Bearer " + os.environ.get("API_KEY")                                       })          
36           return response.json()      
37     def get_data_trading(self, endpoint: str):        
38               """        
39               :param endpoint: {str} only append the endpoint to the base url         
40               :return:         
41               """         
42              response = requests.get(self.url_trading + endpoint,                                 
43                                                         headers={                                     
44                                                                "Authorization": "Bearer "+os.environ.get("API_KEY")                                 })          
45            return response.json()      
46   def put_data(self, endpoint: str):        
47           response = requests.put(self.url_trading + endpoint,                                
48                                                       headers={                                                                          
49                                                  "Authorization": "Bearer " + os.environ.get("API_KEY")                                 })         
50         return response.json()      
51     def post_data(self, endpoint: str, data):         
52         response = requests.post(self.url_trading + endpoint,                                  
53                                                      json.dumps(data),                                 
54                                                      headers={                                      
55                                                              "Authorization": "Bearer " + os.environ.get("API_KEY")                                  })         
56          return response.json()

Determining the Trading Venue

When all base work is done, we can move on and start to actually deal with Trading Venues.

Imagine you want to buy a few shares of your favourite stock, but are unsure about where to begin? We think a good first step is to determine through which Trading Venue you would like to place your order. There are a few reasons why you might choose one venue over another, for example, a larger offering, lower transaction costs or more desirable opening hours. To see which Trading Venues lemon.markets has incorporated, you can use the following request URL, which returns a list of all the venues we offer:

1https://data.lemon.markets/v1/venues/

Use the code snippet below to get a json response in your Python script.

1from helpers import RequestHandler
2class TradingVenues(RequestHandler):
3    def get_all_trading_venues(self):
4        endpoint = 'venues/'
5        response = self.get_data_data(endpoint)
6        print(response)
7if __name__ == "__main__":
8    TradingVenues().get_all_trading_venues()

If you use this endpoint and take a closer look at the request response, you will notice that we currently only support one trading venue. However, keep your eyes peeled for additional trading venues. In the future, we expect lemon.markets to integrate several different stock exchanges, which means even more stocks, bonds, funds, ETFs and warrants from which to choose. Obviously, our users will be the first to know when we integrate additional trading venues.

Besides getting an overview of all available trading venues, you can also retrieve a single trading venue through this endpoint:

1https://data.lemon.markets/v1/venues/?mic={mic}

Again, we are using Python to showcase a specific code snippet. Notice the “{mic}” in the request URL? This is the place where you can specify the trading venue you are interested in. It stands for“Market Identifier Code”.In our script, this is solved by setting an environment variable, which we then use inside the request URL, but you can obviously also set it manually if you are building a different kind of use case.

1import os
2from dotenv import load_dotenv
3from helpers import RequestHandler
4class SingleTradingVenue(RequestHandler):
5    def get_single_trading_venue(self):
6        load_dotenv()
7        mic = os.getenv("MIC")
8        endpoint = f'venues/?mic={mic}'
9        response = self.get_data_data(endpoint)
10        print(response)
11if __name__ == "__main__":
12    SingleTradingVenue().get_single_trading_venue()

Using this endpoint will result in the following response.

1{ 
2  “name”: “Example Stock Exchange”, 
3  “title”: “stex”, 
4  “mic”: “XEXAMPLE”, 
5  “is_open”: true 
6  ...
7}

As you can see, besides general information about the trading venue, the endpoint also returns whether the trading venue is currently open, which in our opinion is a valuable piece of information that you can very easily integrate into your trading strategy. We will come to that in a second and show you a specific example of how you can set up a simple email notification that tells you when a trading venue is closed.

Each Trading Venue has a list of instruments that are tradable there, and you can conveniently find out which ones those are using the following endpoint:

1https://data.lemon.markets/v1/instruments/?mic={mic}&search=SEARCHTERM

In the code snippet below, we are searching for Tesla and the type = stock, but you can also use other query parameters, such as the currency or whether it is currently tradable. Also, you can search for ISIN or WKN if you like those better. The more narrow you define your query parameters, the more specific your results will be.

1import os
2from dotenv import load_dotenv
3from helpers import RequestHandler
4class TradingVenueInstrument(RequestHandler):
5    def get_trading_venue_instruments(self):
6        load_dotenv()
7        mic = os.getenv("MIC")
8        endpoint = f'instruments/?mic={mic}&search=Tesla&type=stock'
9        response = self.get_data_data(endpoint)
10        print(response)
11if __name__ == "__main__":
12    TradingVenueInstrument().get_trading_venue_instruments()

Opening Times

One of the most requested features for our prototype that we launched in autumn last year was the possibility to check trading venue opening times. We took this feedback to heart and integrated just that.

With our API, you have to option to request the opening days and times of a certain Trading Venue. For this, we have built the following endpoint:

1https://data.lemon.markets/v1/venues/?mic={mic}

The code snippet below returns a list of days with specific opening and closing times.

1import os
2from dotenv import load_dotenv
3from helpers import RequestHandler
4class TradingVenueOpeningDays(RequestHandler):
5    def get_trading_venue_opening_days(self):
6        load_dotenv()
7        mic = os.getenv("MIC")
8        endpoint = f'venues/?mic={mic}'
9        response = self.get_data_data(endpoint)
10        opening_days = response['results'][0].get('opening_days', None)
11        print(opening_days)
12if __name__ == "__main__":
13    TradingVenueOpeningDays().get_trading_venue_opening_days()

With the response, you get the current and all future days and you can use that information to adapt your strategy so that it only places orders when the trading venue is actually open. This avoids a scenario where you place an order, only to realise it is a Saturday and the order will not be filled for another two days. Or to place a market order after close, only to have it filled at an undesirable opening price the next morning.

GIF about stating "That is a bummer"

But it does not have to be! By incorporating the opening times of your chosen market, you can configure your strategy such that, for example, unfilled orders expire after market close, no new orders are placed during the most volatile times of the trading day or you are notified when the market opens and closes.

A little Use Case

We at lemon.markets aim to provide you with content that easily lets you start building things and hopefully inspires you to some extent. We created a little Python script that checks whether the trading venue is currently open. If it is, your order is placed. If it is not, you get an automatic email telling you about it. Additionally, the script sends you an automated email at market close that tells you about your positions.

As mentioned above, we use Sendgrid to send emails and we highly recommend you do so as well, as it integrates with your python script perfectly.

As a start, we define a few helper functions:

  1. a function to get the position. For that, we use the positions endpoint, transform the json response into a string and pass it to our “send email” function (see below).
  2. a function to check whether the specific trading venue is currently open. We use the endpoint to retrieve a single trading venue, access the “is_open” attribute and return the boolean value.
  3. a function to activate a placed order. In our API, you will have to activate all orders after you placed them. This helper function takes the Order ID as an input parameter and calls the activate order endpoint afterwards.

Finally, we can define our main function: place_order(). Here, all of our previously defined helper functions come in handy. We first check if the trading venue is currently open. If it is not, we send out an email saying that market is currently closed. If it is, we place our order. Additionally, we wait until the market closes and then send out the email containing our position at market close.

1import os from dotenv 
2import load_dotenvimport json  from helpers 
3import RequestHandler, EmailSenderSendgrid  
4class TradingVenue(RequestHandler):        
5     def send_out_email(self):        
6           load_dotenv()        
7           endpoint = f'positions/'        
8           response = self.get_data_trading(endpoint)        
9           email_text = json.dumps(response)        
10           subject = "Your positions at market close"        
11           EmailSenderSendgrid(email_text, subject)     
12     def check_if_open(self):       
13            """       
14            helper function to check if the trading venue is currently open        
15           :return: {Boolean} is returned that tells whether trading venues is open or closed        
16            """        
17           load_dotenv()        
18           mic = os.getenv("MIC")        
19           endpoint = f'venues/?mic={mic}'        
20           response = self.get_data_data(endpoint)       
21           is_open = response['results'][0].get('is_open', 'It was not possible to retrieve the is_open attribute')        
22         print(is_open)       
23         return is_open     
24    def activate_order(self, order_id):       
25             """        
26             helper function to activate the order once it was placed        :param order_id: the order ID of the order that is to be activated        
27            """        
28           load_dotenv()        
29           endpoint = f'orders/{order_id}/activate/'        
30           response = self.post_data(endpoint, {})        
31           print(response)     def place_order(self):       
32            """        main function that places the specified order        """        
33           load_dotenv()        
34           if not self.check_if_open():            
35                   email_text = "Hey there. You tried to place an order with the lemon.markets API, but the market is currently closed. Please try again later."            
36                   subject = "The market is currently closed"            
37                   EmailSenderSendgrid(email_text, subject)           
38                    return         
39# send notification email if trading venue is closed        
40                    try:            
41                          mic = os.getenv("MIC")             
42                          order_details = {                
43                                    "isin": "DE0008232125",  # ISIN of Lufthansa                
44                                   "expires_at": "p7d",  # specify your timestamp                
45                                   "side": "buy",                
46                                  "quantity": 1,               
47                                 "venue": mic,            }            
48                     endpoint = f'orders/'            
49                     response = self.post_data(endpoint, order_details)            
50                     order_id = response['results'].get('id', 'We were not able to retrieve the order ID.')               
51                     # access helper function to activate the order            
52                     self.activate_order(order_id)            
53                    print('Order was activated')            
54                    # additionally, we send an email with the positions at market close                  
55                    self.send_out_email()        
56           # throw exception in case something goes wrong        
57           except Exception as e:            
58                     print('Placing order not possible', e)  
59if __name__ == "__main__":    
60         TradingVenue().place_order()

Obviously, this little script is only a point of departure for you that shows you how to specifically use our trading venue endpoints to bring more flexibility and stability to your automated trading strategy. If you are interested, take a look at our public GitHub repository that accompanies this blog post and open a pull request. How about we send another email when the market reopens? How about we wait a little bit until we activate the order to get the best possible price? How about we place the order the next morning 2 hours after the trading venue opens. Feel free to play around with it and go crazy 😵. We are super excited to see your ideas.

What else to do with the Trading Venue endpoints?

While we covered a basic use case above, there are a lot of other interesting ideas for our trading venue endpoints.

Perhaps consider connecting your program to your calendar to automatically mark the days on which the market is closed. We suggest calling upon the GET /venues/?mic={mic} endpoint and accessing the opening-days element to obtain all the opening days of a given trading venue. For any day not included in the list, you can assume that the market is closed. You may also want to filter out weekends because we know that the market is closed then. These days can be fed into, for example, the Google Calendar API. Then, using the calendars() and events() resources both a new calendar and corresponding events can be created.

You can also configure your program to send an automated email outlining how your position has performed once the market closes. This can be achieved by requesting the same endpoint as above,GET/venues/?mic={mic}, and when “end” in opening hours matches the current time, to trigger an e-mail notification using the same email resource as in the use case we shared above. In the e-mail, you might want to simply report the overall growth of your position, by comparing the value of your position at market close to that of the day before (try using theGET /positions/endpoint). You might even want to get fancy by measuring performance using a (Python) library such as f.fn(). If you’re not a big fan of receiving emails: how about automatically updating your own trading dashboard at the end of each day with your positions value at the market close? We hate to repeat ourselves, but the possibilities are (almost) endless.

Do you have additional ideas? We would love to hear (and obviously see) what kinds of interesting applications for the Trading Venue endpoints you come up with.

To start building, make sure you sign up to lemon.markets to test out this API concept out in real life. Feel free to reach out to us by leaving a comment, emailing us at support@lemon.markets or joining our growing Slack community.

See you on lemon.markets 🍋

Joanne

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.

Engage

Join lemon.markets community

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

Contribute

Interested in building lemon.markets 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
© lemon.markets 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), lemon.markets 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.