Article

Apply Maximum Drawdown Daily Report for Fund Holding

Raksina Samasiri
Developer Advocate Developer Advocate

Introduction

Maximum Drawdown (MDD) is an indicator of downside risk, with large MDDs suggesting that down movements could be volatile. However, while MDD measures the most significant loss, it does not account for the frequency of losses and the size of any gains.

In this article, we're going to retrieve pricing data of funds from Datastream Python library and calculate their MDDs using Python code.

What can you do with a maximum drawdown?

MDD can be used to measure the risk of losing money from the portfolio performance as it is the most negative cumulative return over a given time period. In other terms, it is the maximum percentage loss that occurred in a return data series, measured as the worst period of "peak to valley" performance for the fund, regardless of whether the drawdown consisted of consecutive months of negative performance. The maximum drawdown is based on simple returns.

The formula to calculate Maximum Drawdown is

Where,

P is the Peak (the highest price) of the period
L is the lowest price of the period

Example of Maximum Drawdown

In this article, we’re going to calculate the MDD with the daily prices of funds. To make it easier to explain, let’s look at this period of the sample fund above. During this period, the 1st peak of this fund is 14.63 AUD, and it decreases to 13.60 AUD, which is the 1st lowest price of the period, then it increases to 14.71 AUD and 14.93 AUD, which are 2nd peak and 5th peak of the period respectively. However, as MDD is the most negative cumulative return over a given time period, the prices to be calculated are the 1st peak and 1st lowest price, not the 5th peak, which is the maximum price during this period (you may see the image above to see the MDD line that shows the most negative cumulative return).

The MDD calculation of this fund is 

Which is around -7.04 (rounded from -7.04032809296)

Now that we know how to calculate the MDD. Let's calculate MDDs of funds using Python code with the data retrieved from the DataStream Python library.

Calculate Maximum Drawdown with Python

We’re going to implement the Python function to calculate MDD, its input data is the dictionary of instruments that contain the dictionary of its price (value) of each date (key), below is an example input with two instruments.

    	
            {('RIC1':
    {'2022-02-22': 14.65,
    {'2022-02-23': 14.61,
    {'2022-02-24': 14.99,
    {'2022-02-25': 15.03,
    {'2022-02-26': 15.31,
    {'2022-02-27': 15.05},
  ('RIC2':
    {'2022-02-22': 4.55,
    {'2022-02-23': 4.61,
    {'2022-02-24': 4.99,
    {'2022-02-25': 5.43,
    {'2022-02-26': 5.31,
    {'2022-02-27': 5.05}}

Here's how we're going to calculate the MDD of each instrument

With the same logic of this flowchart, the code below can be used to get the MDD of each instrument

    	
            

def cal_mdd(price_dict):

    # (1) create Python dictionary to store MDD of each instrument

    mdd = {}

    for _ in price_dict:

        # (2) declare variable to store min and max price of each range

        max_price, min_price = -1, -1

        # (3) create Python list to store drawdown of each range

        mdds = []

        for date in price_dict[_]:

            #print(str(date)+": "+str(price_dict[_][date]))

            price = price_dict[_][date]

            # (4) set new min/max price if this price is higher than current max price

            if price > max_price or max_price == -1:

                if min_price != -1 and max_price != -1:

                    # (5) calculate drawdown % of the previous min-max

                    mdds.append((min_price-max_price)/max_price*100)

                max_price = price

                min_price = -1

            # (6) set only new min price if this price is lower than current min price

            if price < min_price or min_price == -1:

                min_price = price

        # (7) calculate drawdown % of the latest min-max

        mdds.append((min_price-max_price)/max_price*100)

        # (8) store maximum drawdown into Python dictionary with its instrument as a key

        ## use min() function as the drawdowns are less than zero

        mdd[_] = min(mdds)

    return(mdd)

Retrieve and calculate the data using DataStream

In this section, I will walk through a DataStream Web Service example used to retrieve economic indicators by countries. The example uses the DatastreamPy library to connect and retrieve data from Datastream. To use this Python library, please refer to the Getting Started with Python document.

Step 1) Below is the stuff required to get started with DataStream

-  DSWS API service enabled
-  Child ID and password
      -  Your login ID is usually designed to start with Z, have 3 letters and 3 numbers
      -  for example ZXXX123
-  Python 3.6 or above (I’m using Python 3.9.12 here)
-  Python libraries used
      -  DatastreamPy=1.0.10
      -  DateTime=4.4
      -  pandas=1.3.5

Step 2) Searching for the instrument that you’re looking for

The RIC, a ticker-like code used and maintained by Refinitiv to identify financial instruments, is required to get the data of an instrument, to search for the instrument's RIC, the datatype search tool can be used. First, log in with your DataStream credentials. Then type the keyword you’d like to search for (box '1' in the screenshot below). It's shown that the RIC of JPM Japan Equity A Acc USD fund is LP60101474 (boxes '2, 3' in the screenshot below). The ‘P’ button at the bottom left of the search result is the available field of this instrument, which is Price-Trade (box 'available field: Pride - Trade' in the screenshot below)

Step 3) Let's do the coding part

1. Import necessary libraries, which are DatastreamPy for Datastream Python library (for more detail, please check Getting Started with Python) and isnan from math Python library for checking the NaN value in the dataframe

    	
            import DatastreamPy as dsws
from math import isnan

2. Do the authentication with DataStream credentials
Replace <username> with your username and <password> with your password.

    	
            ds = dsws.Datastream(username = '<username>', password = '<password>')
        
        
    

3. Use the code below to get daily price in the last 1 year of these three instruments using DataStream.

Parameter Description Example format
tickers  Tickers here are set to 3 RICs (LP68511418,LP68087222,LP68663339), this can be replace with any RICs of fund tickers = 'RIC1,RIC2,RIC3,...,RICn'
tickers = 'LP68511418,LP68087222,LP68663339'
fields Set to 'X', which is the default value. The default value can be checked using Datastream datatype search tool provided earlier fields = ['FIELD']
fields = ['X']
start Take the date of the last 12 months as a starting point for the data start = '-12M'
end Take today's date as an ending point of the data end = '0M'
freq Frequency of the data, D, which is day is used in this case freq = 'D'
    	
            

df = ds.get_data(tickers = 'LP68511418,LP68087222,LP68663339', fields = ['X']

                 , start = '-12M', end = '0M', freq='D')

display(df)

4. Then we're going to prepare the Python dictionary of price of all the dates of each instrumet by converting the dataframe to Python dictionary and set the RIC as a key, price as a value.

 

    	
            

def data_prep(df):

    price_dict = df.to_dict()

    price_dict = dict((key[0], value) for (key, value) in price_dict.items())

    for date in price_dict:

        price_dict[date] = dict((key, value) for (key, value) in price_dict[date].items() if not isnan(value))

    return(price_dict)

 

price_dict = data_prep(df)

price_dict

5. Calculate MDD of this price_dict with the function defined above

    	
            

mdd_last_1_year = cal_mdd(price_dict)

mdd_last_1_year

Now we already have a Python dictionary named mdd_last_1_year that contain the instrument's RIC as a key and its MDD as a value 

    	
            {'LP68511418': -21.79250166383198,
'LP68087222': -14.638469783164323,
'LP68663339': -36.206896551724135}

What can you do with MDDs?

Let's look at an example of using MDD as a factor to consider investing in any instruments, I'm going to do the backtesting by looking at the yearly MDD of the previous year and select funds with less MDD to be invested, then check the result by checking their return of the previous year to see if it helps me to loss less.

First, we're going to look at the instruments below, which are the active mutual funds in technology in the Lipper Global schema classification with the green strategy.

Instrument Instrument description
LP40221832 AGF Global Sustainable Equity Fund
LP40109383 Artisan Sustainable Emerging Markets Fund
LP40229598 BlackRock Global Impact Fund
LP40229602 BlackRock International Impact Fund
LP40228661 PIMCO Climate Bond Fund
LP40048702 Pax High Yield Bond Fund
LP40221655 Pear Tree Essex Environmental Opportunities Fd
LP40005806 Putnam Sustainable Leaders Fund

From this, we're retrieving their price using Datastream and calculating their MDDs with the same code that was mentioned in the previous section, but with the list of these instruments instead.

    	
            

instruments = 'LP40221832,LP40109383,LP40229598,LP40229602,LP40228661,LP40048702,LP40221655,LP40005806'

 

df_prev_year = ds.get_data(tickers = instruments, fields = ['X']

                 , start = '-24M', end = '-12M', freq='D')

price_dict = data_prep(df_prev_year)

mdd_prev_year = cal_mdd(price_dict)

mdd_prev_year

Here's their yearly MDDs of the last year.

    	
            {'LP40221832': -8.717978107627955,
'LP40109383': -11.370786516853938,
'LP40229598': -10.834371108343701,
'LP40229602': -19.906166219839147,
'LP40228661': -2.4832855778414498,
'LP40048702': -2.2889842632331923,
'LP40221655': -16.933066933066936,
'LP40005806': -8.81461598406788}

Regarding this data, instead of investing in all of the instruments, I'm going to select only the instruments with less MDD (which have a higher value as the MDD is a minus number). Hence, I select half of the instruments with less MDD, which are

Instrument Previous year MDD
LP40221832 -8.717978107627955
LP40228661 -2.4832855778414498
LP40048702 -2.2889842632331923
LP40005806 -8.81461598406788

Next, let's see the result by checking their return for the last year, this data is being retrieved using Eikon Data API (for more detail, check Eikon Data API Overview and its quick start guide)
The code below is used, the data is taken from the field named 'TR.TotalReturn1YrCrossAsset', which is 1-year total return that incorporates the price change and any relevant dividends for the last year.

    	
            

import eikon as ek

 

ek.set_app_key('### Your Eikon App Key ###')

 

year_return, err = ek.get_data(['LP40221832','LP40109383','LP40229598','LP40229602','LP40228661','LP40048702','LP40221655','LP40005806'],

                      ['TR.TotalReturn1YrCrossAsset'])

year_return_dict = dict(zip(year_return['Instrument'], year_return['1 Year Total Return Cross Asset']))

And their returns are as the table below, we could see that the instruments that we decided to invest for are also a top 4 of return compared to other instruments in the list.

No. Instrument Yearly return Decide to invest?
1 LP40221832 -23.2527537 Yes
2 LP40109383 -32.323344 No
3 LP40229598 -32.2921591 No
4 LP40229602 -35.0363303 No
5 LP40228661 -11.3077075 Yes
6 LP40048702 -14.267095 Yes
7 LP40221655 -32.3474739 No
8 LP40005806 -19.5482169 Yes

Conclusion

Regarding the backtesting above, it shows that checking the MDD can help prevent the loss from the investment by avoiding the instruments with the huge MDD. However, in the real scenario, other factors should be considered before the investment as well. Feel free to discover more articles in this developer forum to learn how the data can be used in any cases.

Last but not least, The Maximum Drawdown (MDD) is an indicator of downside risk over a specific time period, which is daily data of the last 1 year in this case. This data can be used to check the fund's past performance to be a part of the factors to consider investing in it. I hope you have fun with this article and if you have any questions or issues regarding API usage, please don’t hesitate to post your question on our Q&A forum

Reference

  • Register or Log in to applaud this article
  • Let the author know how much this article helped you
If you require assistance, please contact us here