1+ #!/usr/bin/env python3
2+ """
3+ Portfolio analysis example using the Borsdata API client.
4+
5+ This example demonstrates how to use the client to analyze a portfolio of stocks.
6+ """
7+
8+ import os
9+ from datetime import datetime , timedelta
10+ from typing import Dict , List , Tuple
11+ import pandas as pd
12+ from dotenv import load_dotenv
13+ from borsdata_client import BorsdataClient , Instrument , StockPrice
14+
15+ # Load environment variables from .env file
16+ load_dotenv ()
17+
18+ # Get API key from environment
19+ api_key = os .getenv ("BORSDATA_API_KEY" )
20+ if not api_key :
21+ raise ValueError ("BORSDATA_API_KEY environment variable not set" )
22+
23+ # Define a sample portfolio (ticker: number of shares)
24+ PORTFOLIO = {
25+ "ERIC B" : 100 , # Ericsson
26+ "VOLV B" : 50 , # Volvo
27+ "SEB A" : 75 , # SEB
28+ }
29+
30+ def get_instrument_by_ticker (client : BorsdataClient , ticker : str ) -> Instrument :
31+ """Find an instrument by its ticker symbol."""
32+ instruments = client .get_instruments ()
33+ for instrument in instruments :
34+ if instrument .ticker == ticker :
35+ return instrument
36+ raise ValueError (f"Instrument with ticker { ticker } not found" )
37+
38+ def get_historical_prices (
39+ client : BorsdataClient ,
40+ instrument_id : int ,
41+ days : int = 365
42+ ) -> List [StockPrice ]:
43+ """Get historical prices for an instrument."""
44+ today = datetime .now ()
45+ start_date = today - timedelta (days = days )
46+
47+ return client .get_stock_prices (
48+ instrument_id = instrument_id ,
49+ from_date = start_date ,
50+ to_date = today
51+ )
52+
53+ def calculate_portfolio_value (
54+ client : BorsdataClient ,
55+ portfolio : Dict [str , int ]
56+ ) -> Tuple [float , Dict [str , float ], pd .DataFrame ]:
57+ """Calculate the current value of a portfolio and its performance."""
58+ total_value = 0.0
59+ stock_values = {}
60+ price_history = {}
61+
62+ # Get data for each stock in the portfolio
63+ for ticker , shares in portfolio .items ():
64+ try :
65+ # Get the instrument
66+ instrument = get_instrument_by_ticker (client , ticker )
67+
68+ # Get historical prices
69+ prices = get_historical_prices (client , instrument .insId )
70+
71+ if not prices :
72+ print (f"No price data available for { ticker } " )
73+ continue
74+
75+ # Get the latest price
76+ latest_price = prices [- 1 ].c
77+ stock_value = latest_price * shares
78+
79+ # Store the results
80+ total_value += stock_value
81+ stock_values [ticker ] = stock_value
82+
83+ # Create a time series of prices
84+ dates = [price .d for price in prices ]
85+ close_prices = [price .c for price in prices ]
86+ price_history [ticker ] = pd .Series (close_prices , index = dates )
87+
88+ print (f"{ ticker } : { shares } shares at { latest_price :.2f} = { stock_value :.2f} " )
89+
90+ except ValueError as e :
91+ print (f"Error processing { ticker } : { e } " )
92+
93+ # Create a DataFrame with all price histories
94+ df = pd .DataFrame (price_history )
95+
96+ # Calculate portfolio value over time (weighted by shares)
97+ portfolio_weights = {}
98+ for ticker , shares in portfolio .items ():
99+ if ticker in df .columns :
100+ portfolio_weights [ticker ] = shares
101+
102+ # Calculate weighted sum
103+ if portfolio_weights :
104+ df ['Portfolio' ] = sum (df [ticker ] * shares for ticker , shares in portfolio_weights .items ())
105+
106+ return total_value , stock_values , df
107+
108+ def main ():
109+ """Run the portfolio analysis example."""
110+ with BorsdataClient (api_key ) as client :
111+ print ("Analyzing portfolio..." )
112+ total_value , stock_values , price_history = calculate_portfolio_value (client , PORTFOLIO )
113+
114+ print ("\n Portfolio Summary:" )
115+ print (f"Total Value: { total_value :.2f} " )
116+
117+ print ("\n Allocation:" )
118+ for ticker , value in stock_values .items ():
119+ percentage = (value / total_value ) * 100 if total_value > 0 else 0
120+ print (f" { ticker } : { value :.2f} ({ percentage :.2f} %)" )
121+
122+ # Calculate performance metrics if we have data
123+ if not price_history .empty and 'Portfolio' in price_history .columns :
124+ portfolio_series = price_history ['Portfolio' ]
125+
126+ # Calculate returns
127+ returns = portfolio_series .pct_change ().dropna ()
128+
129+ print ("\n Performance Metrics:" )
130+ print (f" Start Value: { portfolio_series .iloc [0 ]:.2f} " )
131+ print (f" End Value: { portfolio_series .iloc [- 1 ]:.2f} " )
132+
133+ total_return = (portfolio_series .iloc [- 1 ] / portfolio_series .iloc [0 ] - 1 ) * 100
134+ print (f" Total Return: { total_return :.2f} %" )
135+
136+ annualized_return = ((1 + total_return / 100 ) ** (365 / len (portfolio_series )) - 1 ) * 100
137+ print (f" Annualized Return: { annualized_return :.2f} %" )
138+
139+ volatility = returns .std () * (252 ** 0.5 ) * 100 # Annualized volatility
140+ print (f" Volatility (Annualized): { volatility :.2f} %" )
141+
142+ if volatility > 0 :
143+ sharpe = annualized_return / volatility # Simplified Sharpe ratio (no risk-free rate)
144+ print (f" Sharpe Ratio: { sharpe :.2f} " )
145+
146+ if __name__ == "__main__" :
147+ main ()
0 commit comments