Search code examples
pythonbloombergblpapi

How do I load Bloomberg Live curve in Python


Using xbbg, i try to retrieve the bloomberg swap curve (s23 also known as YCSW0023 Index).

To do so I do :

from xbbg import blp
import asyncio

async def main():
    async for d in blp.live('s23', max_cnt = 1):
        print(d)
    await main()
    
    
main()

But it does only returns :

V:\ABCD.py:16: RuntimeWarning: coroutine 'main' was never awaited
  main()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

Does this mean that I use the wrong ticker ? Does this mean that I use wrong syntax or anything else ?

On excel to retrieve live curve we do :

=BCURVE("S23")

Solution

  • In Excel the BCurve() function is doing a lot of things:

    • resolving the S23 curve id to the YCSW0023 Index curve ticker (probably using the low-level //blp/instruments Bloomberg api service)
    • getting the curve members using one of the bulk data fields (possibly PAR_CURVE)
    • Listing the curve instruments, tenor and type on the spreadsheet
    • Creating individual bdp function calls in the cells which depend on the instrument type: some will be 'live' streaming prices, but others (eg fixings) will not; some will convert futures price to rate, some will not.

    How you handle this will depend on what end-use you have for the curve. Do you want a one-off snapshot of the latest rates, or do you want live rates to keep ticking away in the background, constantly updating the curve?

    Since I can't guess your exact requirement, here is a possible example (I have left out the curve id / curve ticker conversion). This should at least give you a starting point for the various functions.

    from xbbg import blp
    import asyncio
    import re
    
    async def getTicks(result, tkrs):
        remaining = len(tkrs)
        async for tick in blp.live(tkrs,flds=['BID'],max_cnt=0):       
            tkr = tick['TICKER']
            res = result[tkr]
    
            if res['Rate'] is None:
                remaining -= 1
    
            #Change futures prices to rates
            if res['Type'] == 'FUTURE_RATE':
                res['Rate'] = 100 - tick['BID']
            else:
                res['Rate'] = tick['BID']
    
            #Break out if have a rate for all tickers
            if remaining <= 0: break
    
    curveTicker = 'YCSW0023 Index'
    
    #Get the bulk data for par curve members
    members = blp.bds(curveTicker,'PAR_CURVE')
    
    tickers = [re.sub(' +', ' ',tkr) for tkr in members.ticker] #Get rid of extra spaces in ticker
    tenors = [tnr for tnr in members.tenor]
    types = [typ for typ in members.point_type]
    
    results = { tickers[n]:{'Tenor':tenors[n],'Type': types[n],'Rate':None} for n in range(len(tickers))}
    
    live_tickers = []
    #Use bdp() for non-live rates (eg fixings)
    for tkr in results:
        res = results[tkr]
        if res['Type'] == 'CASH':
            res['Rate'] = blp.bdp(tkr,'PX_LAST').iloc[0][0]
        else:
            live_tickers.append(tkr)
    
    #Kick off the capture of the live subscriptions
    asyncio.run(getTicks(results,live_tickers))
    
    for inst in results:
        print(inst,results[inst])
    

    With the output:

    US0003M Index {'Tenor': '3 MO', 'Type': 'CASH', 'Rate': 2.9210000000000003}
    EDU2 Comdty {'Tenor': '128 DY', 'Type': 'FUTURE_RATE', 'Rate': 3.3299999999999983}
    EDZ2 Comdty {'Tenor': '212 DY', 'Type': 'FUTURE_RATE', 'Rate': 3.8400000000000034}
    EDH3 Comdty {'Tenor': '310 DY', 'Type': 'FUTURE_RATE', 'Rate': 3.7900000000000063}
    EDM3 Comdty {'Tenor': '401 DY', 'Type': 'FUTURE_RATE', 'Rate': 3.6500000000000057}
    EDU3 Comdty {'Tenor': '492 DY', 'Type': 'FUTURE_RATE', 'Rate': 3.424999999999997}
    EDZ3 Comdty {'Tenor': '583 DY', 'Type': 'FUTURE_RATE', 'Rate': 3.219999999999999}
    USSWAP2 Curncy {'Tenor': '2 YR', 'Type': 'SWAP', 'Rate': 3.4258}
    USSWAP3 Curncy {'Tenor': '3 YR', 'Type': 'SWAP', 'Rate': 3.1821}
    USSWAP4 Curncy {'Tenor': '4 YR', 'Type': 'SWAP', 'Rate': 3.0191}
    USSWAP5 Curncy {'Tenor': '5 YR', 'Type': 'SWAP', 'Rate': 2.9225}
    USSW6 Curncy {'Tenor': '6 YR', 'Type': 'SWAP', 'Rate': 2.8721}
    USSWAP7 Curncy {'Tenor': '7 YR', 'Type': 'SWAP', 'Rate': 2.8436}
    USSW8 Curncy {'Tenor': '8 YR', 'Type': 'SWAP', 'Rate': 2.8264}
    USSW9 Curncy {'Tenor': '9 YR', 'Type': 'SWAP', 'Rate': 2.8231}
    USSWAP10 Curncy {'Tenor': '10 YR', 'Type': 'SWAP', 'Rate': 2.8309}
    USSWAP11 Curncy {'Tenor': '11 YR', 'Type': 'SWAP', 'Rate': 2.852}
    USSWAP12 Curncy {'Tenor': '12 YR', 'Type': 'SWAP', 'Rate': 2.8632}
    USSWAP15 Curncy {'Tenor': '15 YR', 'Type': 'SWAP', 'Rate': 2.9057}
    USSWAP20 Curncy {'Tenor': '20 YR', 'Type': 'SWAP', 'Rate': 2.9057}
    USSWAP25 Curncy {'Tenor': '25 YR', 'Type': 'SWAP', 'Rate': 2.8384}
    USSWAP30 Curncy {'Tenor': '30 YR', 'Type': 'SWAP', 'Rate': 2.7625}
    USSWAP40 Curncy {'Tenor': '40 YR', 'Type': 'SWAP', 'Rate': 2.5562}
    USSWAP50 Curncy {'Tenor': '50 YR', 'Type': 'SWAP', 'Rate': 2.3034}