Creación de una herramienta avanzada de análisis de cartera e inteligencia de mercado con OpenBB

En este tutorial, nos sumergimos en las capacidades avanzadas de Abrebb para realizar análisis integrales de cartera e inteligencia de mercado. Comenzamos construyendo una cartera centrada en la tecnología, obteniendo datos históricos del mercado y calculando las métricas de rendimiento clave. Luego exploramos indicadores técnicos avanzados, desempeño a nivel del sector, sentimiento de mercado y análisis de riesgos basado en correlación. En el camino, integramos visualizaciones e ideas para hacer que el análisis sea más intuitivo y procesable, asegurando que cubramos los aspectos cuantitativos y cualitativos de la toma de decisiones de inversión. Mira el Códigos completos aquí.

!pip install openbb[all] --quiet


import warnings
warnings.filterwarnings('ignore')


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
import openbb


from openbb import obb


pd.set_option('display.max_columns', None)
pd.set_option('display.width', 1000)


print("🚀 Advanced OpenBB Financial Analysis Tutorial")
print("=" * 60)

Comenzamos instalando e importando OpenBB junto con bibliotecas esenciales de Python para análisis y visualización de datos. Configuramos nuestro entorno para suprimir las advertencias, establecer opciones de visualización para pandas y prepararnos para realizar análisis financieros avanzados. Mira el Códigos completos aquí.

print("\n📊 1. BUILDING AND ANALYZING A TECH PORTFOLIO")
print("-" * 50)


tech_stocks = ['AAPL', 'GOOGL', 'MSFT', 'TSLA', 'NVDA']
initial_weights = [0.25, 0.20, 0.25, 0.15, 0.15]


end_date = datetime.now().strftime('%Y-%m-%d')
start_date = (datetime.now() - timedelta(days=365)).strftime('%Y-%m-%d')


portfolio_data = {}
portfolio_returns = pd.DataFrame()
successful_stocks = []


print(f"Fetching data from {start_date} to {end_date}...")


for i, symbol in enumerate(tech_stocks):
   try:
       data = obb.equity.price.historical(symbol=symbol, start_date=start_date, end_date=end_date)
       df = data.to_df()
      
       if df.index.duplicated().any():
           df = df[~df.index.duplicated(keep='first')]
      
       portfolio_data[symbol] = df
      
       returns = df['close'].pct_change().dropna()
       portfolio_returns[symbol] = returns
       successful_stocks.append(symbol)
      
       print(f"✅ {symbol}: {len(df)} days of data")
   except Exception as e:
       print(f"❌ Error fetching {symbol}: {str(e)}")


if successful_stocks:
   successful_indices = [tech_stocks.index(stock) for stock in successful_stocks]
   portfolio_weights = [initial_weights[i] for i in successful_indices]
   total_weight = sum(portfolio_weights)
   portfolio_weights = [w/total_weight for w in portfolio_weights]
  
   print(f"\n📋 Portfolio composition (normalized weights):")
   for stock, weight in zip(successful_stocks, portfolio_weights):
       print(f"  {stock}: {weight:.1%}")
else:
   portfolio_weights = []


print("\n📈 2. PORTFOLIO PERFORMANCE ANALYSIS")
print("-" * 50)


if not portfolio_returns.empty and portfolio_weights:
   weighted_returns = (portfolio_returns * portfolio_weights).sum(axis=1)
  
   annual_return = weighted_returns.mean() * 252
   annual_volatility = weighted_returns.std() * np.sqrt(252)
   sharpe_ratio = annual_return / annual_volatility if annual_volatility > 0 else 0
   max_drawdown = (weighted_returns.cumsum().expanding().max() - weighted_returns.cumsum()).max()
  
   print(f"Portfolio Annual Return: {annual_return:.2%}")
   print(f"Portfolio Volatility: {annual_volatility:.2%}")
   print(f"Sharpe Ratio: {sharpe_ratio:.3f}")
   print(f"Max Drawdown: {max_drawdown:.2%}")
  
   print("\n📊 Individual Stock Performance:")
   for stock in successful_stocks:
       stock_return = portfolio_returns[stock].mean() * 252
       stock_vol = portfolio_returns[stock].std() * np.sqrt(252)
       print(f"{stock}: Return {stock_return:.2%}, Volatility {stock_vol:.2%}")
else:
   print("❌ No valid portfolio data available for analysis")

Construimos una cartera de tecnología, obtenemos un año de precios con OpenBB, calculamos los pesos normalizados y los rendimientos diarios, luego evaluamos el rendimiento, el rendimiento anual, la volatilidad, el sharpe, el retraso máximo y revisan las estadísticas de acciones en tiempo real. Mira el Códigos completos aquí.

print("\n🔍 3. ADVANCED TECHNICAL ANALYSIS")
print("-" * 50)


symbol="NVDA"
try:
   price_data = obb.equity.price.historical(symbol=symbol, start_date=start_date, end_date=end_date)
   df = price_data.to_df()
  
   df['SMA_20'] = df['close'].rolling(window=20).mean()
   df['SMA_50'] = df['close'].rolling(window=50).mean()
   df['EMA_12'] = df['close'].ewm(span=12).mean()
   df['EMA_26'] = df['close'].ewm(span=26).mean()
  
   df['MACD'] = df['EMA_12'] - df['EMA_26']
   df['MACD_signal'] = df['MACD'].ewm(span=9).mean()
  
   delta = df['close'].diff()
   gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
   loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
   rs = gain / loss
   df['RSI'] = 100 - (100 / (1 + rs))
  
   df['BB_middle'] = df['close'].rolling(window=20).mean()
   bb_std = df['close'].rolling(window=20).std()
   df['BB_upper'] = df['BB_middle'] + (bb_std * 2)
   df['BB_lower'] = df['BB_middle'] - (bb_std * 2)
  
   current_price = df['close'].iloc[-1]
   current_rsi = df['RSI'].iloc[-1]
   macd_signal = "BUY" if df['MACD'].iloc[-1] > df['MACD_signal'].iloc[-1] else "SELL"
   price_vs_sma20 = "Above" if current_price > df['SMA_20'].iloc[-1] else "Below"
  
   print(f"\n{symbol} Technical Analysis:")
   print(f"Current Price: ${current_price:.2f}")
   print(f"RSI (14): {current_rsi:.2f} ({'Overbought' if current_rsi > 70 else 'Oversold' if current_rsi < 30 else 'Neutral'})")
   print(f"MACD Signal: {macd_signal}")
   print(f"Price vs SMA(20): {price_vs_sma20}")
  
except Exception as e:
   print(f"Error in technical analysis: {str(e)}")


print("\n🏭 4. SECTOR ANALYSIS & STOCK SCREENING")
print("-" * 50)


sectors = {
   'Technology': ['AAPL', 'GOOGL', 'MSFT'],
   'Electric Vehicles': ['TSLA', 'RIVN', 'LCID'],
   'Semiconductors': ['NVDA', 'AMD', 'INTC']
}


sector_performance = {}


for sector_name, stocks in sectors.items():
   sector_returns = []
   for stock in stocks:
       try:
           data = obb.equity.price.historical(symbol=stock, start_date=start_date, end_date=end_date)
           df = data.to_df()
           if df.index.duplicated().any():
               df = df[~df.index.duplicated(keep='first')]
           returns = df['close'].pct_change().dropna()
           sector_returns.append(returns.mean() * 252)
       except Exception as e:
           print(f"❌ Failed to fetch {stock}: {str(e)}")
           continue
  
   if sector_returns:
       avg_return = np.mean(sector_returns)
       sector_performance[sector_name] = avg_return
       print(f"{sector_name}: {avg_return:.2%} average annual return")


print("\n📰 5. MARKET SENTIMENT ANALYSIS")
print("-" * 50)


for symbol in successful_stocks[:2]: 
   try:
       news = obb.news.company(symbol=symbol, limit=3)
       news_df = news.to_df()
       print(f"\n{symbol} Recent News Headlines:")
       for idx, row in news_df.iterrows():
           print(f"• {row.get('title', 'N/A')[:80]}...")
           break 
   except Exception as e:
       print(f"News not available for {symbol}: {str(e)}")

Ejecutamos un análisis técnico avanzado en NVDA, calculando las bandas SMA, EMA, MACD, RSI y Bollinger, para medir el impulso y las posibles señales de entrada/salida. Luego evaluamos los sectores mediante rendimientos anualizados en tecnología, EV y semiconductores, y tiramos de los titulares de la compañía frescos para doblar el sentimiento del mercado en nuestra tesis. Mira el Códigos completos aquí.

print("\n⚠️  6. RISK ANALYSIS")
print("-" * 50)


if not portfolio_returns.empty and len(portfolio_returns.columns) > 1:
   correlation_matrix = portfolio_returns.corr()
   print("\nPortfolio Correlation Matrix:")
   print(correlation_matrix.round(3))
  
   portfolio_var = np.dot(portfolio_weights, np.dot(correlation_matrix *
                         (portfolio_returns.std().values.reshape(-1,1) *
                          portfolio_returns.std().values.reshape(1,-1)),
                         portfolio_weights))
   portfolio_risk = np.sqrt(portfolio_var) * np.sqrt(252)
   print(f"\nPortfolio Risk (Volatility): {portfolio_risk:.2%}")


print("\n📊 7. CREATING PERFORMANCE VISUALIZATIONS")
print("-" * 50)


if not portfolio_returns.empty:
   fig, axes = plt.subplots(2, 2, figsize=(15, 10))
   fig.suptitle('Portfolio Analysis Dashboard', fontsize=16)
  
   cumulative_returns = (1 + portfolio_returns).cumprod()
   cumulative_returns.plot(ax=axes[0,0], title="Cumulative Returns", alpha=0.7)
   axes[0,0].legend(bbox_to_anchor=(1.05, 1), loc="upper left")
  
   rolling_vol = portfolio_returns.rolling(window=30).std() * np.sqrt(252)
   rolling_vol.plot(ax=axes[0,1], title="30-Day Rolling Volatility", alpha=0.7)
   axes[0,1].legend(bbox_to_anchor=(1.05, 1), loc="upper left")
  
   weighted_returns.hist(bins=50, ax=axes[1,0], alpha=0.7)
   axes[1,0].set_title('Portfolio Returns Distribution')
   axes[1,0].axvline(weighted_returns.mean(), color="red", linestyle="--", label="Mean")
   axes[1,0].legend()
  
   if len(correlation_matrix) > 1:
       sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0, ax=axes[1,1])
       axes[1,1].set_title('Correlation Matrix')
  
   plt.tight_layout()
   plt.show()


print("\n🎯 8. INVESTMENT SUMMARY & RECOMMENDATIONS")
print("-" * 50)


print("Portfolio Analysis Complete!")
print(f"✅ Analyzed {len(successful_stocks)} stocks")
print(f"✅ Calculated {len(sector_performance)} sector performances")
print(f"✅ Generated technical indicators and risk metrics")


if not portfolio_returns.empty and len(successful_stocks) > 0:
   best_performer = portfolio_returns.mean().idxmax()
   worst_performer = portfolio_returns.mean().idxmin()
   print(f"🏆 Best Performer: {best_performer}")
   print(f"📉 Worst Performer: {worst_performer}")


print("\n💡 Key Insights:")
print("• Diversification across tech sectors reduces portfolio risk")
print("• Technical indicators help identify entry/exit points")
print("• Regular rebalancing maintains target allocations")
print("• Monitor correlations to avoid concentration risk")


print("\n🔧 Next Steps:")
print("• Backtest different allocation strategies")
print("• Add fundamental analysis metrics")
print("• Implement automated alerts for technical signals")
print("• Explore ESG and factor-based screening")


print("\n" + "="*60)
print("OpenBB Advanced Tutorial Complete! 🎉")
print("Visit https://openbb.co for more features and documentation")

Cuantificamos el riesgo de cartera a través de correlaciones y volatilidad anualizada, visualizamos el rendimiento con rendimientos acumulativos, volatilidad rodante, distribución de retorno y un mapa de calor de correlación, luego concluyen con el mejor/peor desempeño, las ideas clave (diversificación, señales, reequilibrio) y los siguientes pasos de concreto como el revés, agregar fundamentos, alertas y alertas de ESG.

En conclusión, hemos aprovechado con éxito OpenBB para construir, analizar y visualizar una cartera diversificada al extraer información del sector, señales técnicas y métricas de riesgo. Vemos cómo la combinación de estadísticas de rendimiento con el sentimiento del mercado y las visualizaciones avanzadas nos permite tomar decisiones de inversión informadas. Este enfoque nos permite monitorear y refinar continuamente nuestras estrategias, asegurando que sigamos siendo ágiles en las condiciones cambiantes del mercado y seguramente en las elecciones basadas en datos que tomamos.


Sana Hassan, una pasante de consultoría en MarktechPost y estudiante de doble grado en IIT Madras, le apasiona aplicar tecnología e IA para abordar los desafíos del mundo real. Con un gran interés en resolver problemas prácticos, aporta una nueva perspectiva a la intersección de la IA y las soluciones de la vida real.