← Zurück zu den Artikeln
September 25, 2025
5 min read

Markowitz-Portfoliotheorie für Krypto: Vom Anfänger zum Experten

Markowitz-Portfoliotheorie für Krypto: Vom Anfänger zum Experten
#portfolio optimization
#Markowitz
#crypto
#Python
#quantitative finance
#risk management
#diversification
#efficient frontier
#Sharpe ratio
#algorithmic trading
📊
Part 1 of 5 · Collection
Portfolio Construction & Risk

Optimale Krypto-Portfolios mit Python aufbauen - denn YOLO ist keine Strategie

Markowitz Portfolio Theory Markowitz-Portfoliotheorie: Mathematische Optimierung, angewendet auf digitale Assets, um die Rendite bei einem gegebenen Risikoniveau zu maximieren.


Einleitung: Warum dein Krypto-Portfolio Mathematik braucht (nicht nur Bauchgefühl)

Hey Crypto-Degens! 👋

Erinnerst du dich noch daran, wie du deinen gesamten Stack in DOGE geworfen hast, weil Elon getwittert hat? Oder als du beim letzten Crash panisch alles verkauft hast? Ja, das kennen wir alle. Heute sprechen wir über etwas, das dein Portfolio (und deinen Verstand) retten könnte: die Markowitz-Portfoliotheorie.

Harry Markowitz hat dafür 1990 tatsächlich den Nobelpreis gewonnen. Die Grundidee? Man kann sein Portfolio mathematisch optimieren, um die bestmögliche Rendite für ein beliebiges Risikoniveau zu erzielen. Es ist wie ein GPS für deine Investments, statt blind durch die Gegend zu fahren.

Das Kernkonzept: Risiko vs. Rendite (der ewige Tanz)

Bevor wir in den Code eintauchen, sollten wir verstehen, womit wir es zu tun haben:

  • Erwartete Rendite: Wie viel Geld du zu verdienen erwartest
  • Risiko (Volatilität): Wie stark der Wert deines Portfolios schwankt
  • Korrelation: Wie ähnlich sich verschiedene Assets zueinander bewegen

Die Magie entsteht, wenn du Assets kombinierst, die sich nicht perfekt synchron bewegen. Wenn Bitcoin abstürzt, halten sich manche DeFi-Token vielleicht besser. Das ist Diversifikation, die für dich arbeitet.

Risk vs Return Risiko vs. Rendite: Ausbalancieren volatiler Assets mit hoher Rendite und einer stabilen Grundlage, um die optimale geometrische mittlere Rendite zu erreichen.

Unsere Python-Umgebung einrichten

Zuerst das Wichtigste - machen wir unsere Werkzeuge bereit:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.optimize import minimize
import yfinance as yf
import warnings
warnings.filterwarnings('ignore')

plt.style.use('dark_background')
sns.set_palette("husl")

Stufe 1: Erste Schritte - Einfache Portfolio-Mathematik

Beginnen wir mit den Grundlagen. Wir berechnen Rendite und Risiko für ein einfaches Portfolio aus zwei Assets.

def get_crypto_data(symbols, period="1y"):
    """
    Fetch crypto data from Yahoo Finance
    symbols: list of crypto symbols (e.g., ['BTC-USD', 'ETH-USD'])
    period: time period for data
    """
    data = yf.download(symbols, period=period)['Adj Close']
    return data

crypto_symbols = ['BTC-USD', 'ETH-USD']
prices = get_crypto_data(crypto_symbols)

returns = prices.pct_change().dropna()
print("Daily Returns Preview:")
print(returns.head())

Jetzt berechnen wir ein paar grundlegende Portfolio-Kennzahlen:

def portfolio_performance(weights, returns):
    """
    Calculate portfolio return and volatility
    weights: array of portfolio weights
    returns: dataframe of asset returns
    """
    portfolio_return = np.sum(returns.mean() * weights) * 252

    portfolio_vol = np.sqrt(np.dot(weights.T, np.dot(returns.cov() * 252, weights)))

    return portfolio_return, portfolio_vol

weights_5050 = np.array([0.5, 0.5])
ret_5050, vol_5050 = portfolio_performance(weights_5050, returns)

print(f"50/50 Portfolio:")
print(f"Expected Annual Return: {ret_5050:.2%}")
print(f"Annual Volatility: {vol_5050:.2%}")
print(f"Sharpe Ratio: {ret_5050/vol_5050:.3f}")

Stufe 2: Es wird ernst - Die Effizienzgrenze

Jetzt geht's ans Eingemachte! Die Effizienzgrenze zeigt uns alle möglichen optimalen Portfolios. Jeder Punkt steht für die bestmögliche Rendite bei einem gegebenen Risikoniveau.

def generate_random_portfolios(returns, num_portfolios=10000):
    """
    Generate random portfolio combinations
    """
    num_assets = len(returns.columns)
    results = np.zeros((4, num_portfolios))

    for i in range(num_portfolios):
        weights = np.random.random(num_assets)
        weights /= np.sum(weights)  # Normalize to sum to 1

        portfolio_return, portfolio_vol = portfolio_performance(weights, returns)
        sharpe_ratio = portfolio_return / portfolio_vol

        results[0,i] = portfolio_return
        results[1,i] = portfolio_vol
        results[2,i] = sharpe_ratio
        results[3,i:] = weights

    return results

results = generate_random_portfolios(returns)

portfolio_results = pd.DataFrame({
    'Returns': results[0],
    'Volatility': results[1],
    'Sharpe_Ratio': results[2]
})

plt.figure(figsize=(12, 8))
scatter = plt.scatter(portfolio_results['Volatility'],
                     portfolio_results['Returns'],
                     c=portfolio_results['Sharpe_Ratio'],
                     cmap='viridis', alpha=0.6)
plt.colorbar(scatter, label='Sharpe Ratio')
plt.xlabel('Volatility (Risk)')
plt.ylabel('Expected Return')
plt.title('Efficient Frontier - Random Portfolios')
plt.show()

Efficient Frontier Die Effizienzgrenze: Die Kurve, die die maximal mögliche erwartete Rendite für ein gegebenes Risikoniveau darstellt.

Stufe 3: Optimierungs-Meister - Das perfekte Portfolio finden

Zufallsstichproben machen Spaß, aber wir wollen die mathematisch optimale Lösung. Zeit, die großen Geschütze aufzufahren - scipy-Optimierung!

def negative_sharpe_ratio(weights, returns, risk_free_rate=0.02):
    """
    Calculate negative Sharpe ratio (we minimize this)
    """
    portfolio_return, portfolio_vol = portfolio_performance(weights, returns)
    sharpe = (portfolio_return - risk_free_rate) / portfolio_vol
    return -sharpe

def minimize_volatility(weights, returns):
    """
    Calculate portfolio volatility (we minimize this)
    """
    _, portfolio_vol = portfolio_performance(weights, returns)
    return portfolio_vol

def portfolio_return_objective(weights, returns):
    """
    Calculate portfolio return (we maximize this)
    """
    portfolio_return, _ = portfolio_performance(weights, returns)
    return -portfolio_return  # Negative because we minimize

def optimize_portfolio(returns, objective='sharpe', target_return=None):
    """
    Optimize portfolio based on different objectives
    """
    num_assets = len(returns.columns)

    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})  # Weights sum to 1
    bounds = tuple((0, 1) for _ in range(num_assets))  # No short selling

    initial_guess = num_assets * [1. / num_assets]

    if objective == 'sharpe':
        result = minimize(negative_sharpe_ratio, initial_guess,
                         args=(returns,), method='SLSQP',
                         bounds=bounds, constraints=constraints)

    elif objective == 'min_vol':
        result = minimize(minimize_volatility, initial_guess,
                         args=(returns,), method='SLSQP',
                         bounds=bounds, constraints=constraints)

    elif objective == 'target_return':
        constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1},
                      {'type': 'eq', 'fun': lambda x: portfolio_performance(x, returns)[0] - target_return})

        result = minimize(minimize_volatility, initial_guess,
                         args=(returns,), method='SLSQP',
                         bounds=bounds, constraints=constraints)

    return result

max_sharpe = optimize_portfolio(returns, 'sharpe')
min_vol = optimize_portfolio(returns, 'min_vol')

print("🎯 Maximum Sharpe Ratio Portfolio:")
for i, symbol in enumerate(crypto_symbols):
    print(f"{symbol}: {max_sharpe.x[i]:.3f}")

ret_sharpe, vol_sharpe = portfolio_performance(max_sharpe.x, returns)
print(f"Return: {ret_sharpe:.2%}, Volatility: {vol_sharpe:.2%}")
print(f"Sharpe Ratio: {ret_sharpe/vol_sharpe:.3f}\n")

print("🛡️ Minimum Volatility Portfolio:")
for i, symbol in enumerate(crypto_symbols):
    print(f"{symbol}: {min_vol.x[i]:.3f}")

ret_minvol, vol_minvol = portfolio_performance(min_vol.x, returns)
print(f"Return: {ret_minvol:.2%}, Volatility: {vol_minvol:.2%}")

Stufe 4: Multi-Asset-Wahnsinn - Ein echtes Krypto-Portfolio

Skalieren wir das jetzt auf ein richtiges Krypto-Portfolio mit mehreren Assets:

crypto_portfolio = ['BTC-USD', 'ETH-USD', 'BNB-USD', 'ADA-USD', 'SOL-USD', 'DOT-USD']
prices_multi = get_crypto_data(crypto_portfolio, period="2y")
returns_multi = prices_multi.pct_change().dropna()

correlation_matrix = returns_multi.corr()

plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, annot=True, cmap='RdYlBu_r', center=0)
plt.title('Crypto Asset Correlation Matrix')
plt.show()

def efficient_frontier(returns, num_portfolios=50):
    """
    Calculate the efficient frontier
    """
    ret_range = np.linspace(returns.mean().min()*252, returns.mean().max()*252, num_portfolios)

    efficient_portfolios = []

    for target_ret in ret_range:
        try:
            result = optimize_portfolio(returns, 'target_return', target_ret)
            if result.success:
                ret, vol = portfolio_performance(result.x, returns)
                efficient_portfolios.append([ret, vol, result.x])
        except:
            continue

    return np.array(efficient_portfolios)

efficient_port = efficient_frontier(returns_multi)

plt.figure(figsize=(14, 10))

random_results = generate_random_portfolios(returns_multi, 5000)
plt.scatter(random_results[1], random_results[0],
           c=random_results[2], cmap='viridis', alpha=0.3, s=10)

if len(efficient_port) > 0:
    plt.plot(efficient_port[:,1], efficient_port[:,0], 'r-', linewidth=3, label='Efficient Frontier')

max_sharpe_multi = optimize_portfolio(returns_multi, 'sharpe')
min_vol_multi = optimize_portfolio(returns_multi, 'min_vol')

ret_sharpe_multi, vol_sharpe_multi = portfolio_performance(max_sharpe_multi.x, returns_multi)
ret_minvol_multi, vol_minvol_multi = portfolio_performance(min_vol_multi.x, returns_multi)

plt.scatter(vol_sharpe_multi, ret_sharpe_multi, marker='*', color='gold', s=500, label='Max Sharpe')
plt.scatter(vol_minvol_multi, ret_minvol_multi, marker='*', color='red', s=500, label='Min Volatility')

plt.colorbar(label='Sharpe Ratio')
plt.xlabel('Volatility (Risk)')
plt.ylabel('Expected Return')
plt.title('Multi-Asset Crypto Portfolio Optimization')
plt.legend()
plt.show()

print("🚀 Optimal Multi-Asset Allocations:")
print("\nMaximum Sharpe Ratio Portfolio:")
sharpe_weights = pd.Series(max_sharpe_multi.x, index=crypto_portfolio).sort_values(ascending=False)
for asset, weight in sharpe_weights.items():
    if weight > 0.01:  # Only show significant allocations
        print(f"{asset}: {weight:.1%}")

print(f"\nPortfolio Metrics:")
print(f"Expected Return: {ret_sharpe_multi:.1%}")
print(f"Volatility: {vol_sharpe_multi:.1%}")
print(f"Sharpe Ratio: {ret_sharpe_multi/vol_sharpe_multi:.2f}")

Multi-Asset Portfolio Optimization Multi-Asset-Diversifikation: Aufbau eines robusten Portfolios durch Kombination unkorrelierter Krypto-Assets zu einer stabilen geometrischen Struktur.

Stufe 5: Fortgeschrittene Techniken - Black-Litterman und Risikoparität

Für die wahren Ninjas der Portfoliooptimierung implementieren wir jetzt einige fortgeschrittene Techniken:

def risk_parity_portfolio(returns):
    """
    Risk Parity Portfolio - each asset contributes equally to portfolio risk
    """
    def risk_contribution(weights, cov_matrix):
        portfolio_vol = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
        marginal_contrib = np.dot(cov_matrix, weights) / portfolio_vol
        contrib = weights * marginal_contrib
        return contrib

    def risk_parity_objective(weights, cov_matrix):
        contrib = risk_contribution(weights, cov_matrix)
        target_contrib = np.ones(len(weights)) / len(weights)
        return np.sum((contrib - target_contrib)**2)

    num_assets = len(returns.columns)
    cov_matrix = returns.cov() * 252

    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bounds = tuple((0.001, 1) for _ in range(num_assets))
    initial_guess = num_assets * [1. / num_assets]

    result = minimize(risk_parity_objective, initial_guess,
                     args=(cov_matrix,), method='SLSQP',
                     bounds=bounds, constraints=constraints)

    return result

risk_parity_result = risk_parity_portfolio(returns_multi)

print("⚖️ Risk Parity Portfolio:")
rp_weights = pd.Series(risk_parity_result.x, index=crypto_portfolio).sort_values(ascending=False)
for asset, weight in rp_weights.items():
    print(f"{asset}: {weight:.1%}")

ret_rp, vol_rp = portfolio_performance(risk_parity_result.x, returns_multi)
print(f"\nRisk Parity Metrics:")
print(f"Expected Return: {ret_rp:.1%}")
print(f"Volatility: {vol_rp:.1%}")
print(f"Sharpe Ratio: {ret_rp/vol_rp:.2f}")

def backtest_portfolio(weights, prices):
    """
    Simple backtest of portfolio performance
    """
    returns = prices.pct_change().dropna()
    portfolio_returns = (returns * weights).sum(axis=1)

    cumulative_returns = (1 + portfolio_returns).cumprod()

    total_return = cumulative_returns.iloc[-1] - 1
    annualized_return = (1 + total_return) ** (252 / len(portfolio_returns)) - 1
    annualized_vol = portfolio_returns.std() * np.sqrt(252)
    sharpe_ratio = annualized_return / annualized_vol

    max_dd = (cumulative_returns / cumulative_returns.expanding().max() - 1).min()

    return {
        'total_return': total_return,
        'annualized_return': annualized_return,
        'annualized_volatility': annualized_vol,
        'sharpe_ratio': sharpe_ratio,
        'max_drawdown': max_dd,
        'cumulative_returns': cumulative_returns
    }

strategies = {
    'Max Sharpe': max_sharpe_multi.x,
    'Min Volatility': min_vol_multi.x,
    'Risk Parity': risk_parity_result.x,
    'Equal Weight': np.ones(len(crypto_portfolio)) / len(crypto_portfolio)
}

plt.figure(figsize=(14, 8))

for name, weights in strategies.items():
    backtest_results = backtest_portfolio(weights, prices_multi)
    plt.plot(backtest_results['cumulative_returns'], label=f"{name} (Sharpe: {backtest_results['sharpe_ratio']:.2f})")

plt.title('Portfolio Strategy Backtests')
plt.xlabel('Date')
plt.ylabel('Cumulative Returns')
plt.legend()
plt.yscale('log')
plt.grid(True, alpha=0.3)
plt.show()

![Portfolio Strategy Backtests](/images/blog/markowitz-backtest.webp)
*Algorithmisches Backtesting: Simulation historischer Performance zur Validierung theoretischer Optimierungsmodelle.*


performance_summary = pd.DataFrame()
for name, weights in strategies.items():
    results = backtest_portfolio(weights, prices_multi)
    performance_summary[name] = [
        f"{results['annualized_return']:.1%}",
        f"{results['annualized_volatility']:.1%}",
        f"{results['sharpe_ratio']:.2f}",
        f"{results['max_drawdown']:.1%}"
    ]

performance_summary.index = ['Annual Return', 'Annual Volatility', 'Sharpe Ratio', 'Max Drawdown']
print("\n📊 Strategy Performance Summary:")
print(performance_summary)

Der Realitätscheck: Was Markowitz dir nicht verrät

Bevor du voll auf mathematische Optimierung setzt, hier ein paar harte Wahrheiten über Krypto:

1. Vergangene Performance ≠ Zukünftige Ergebnisse Der Kryptomarkt ist jung und chaotisch. Die Korrelationen, die du berechnet hast? Die können sich über Nacht umkehren, wenn sich Regulierungen ändern oder der nächste große Hack passiert.

2. Transaktionskosten spielen eine Rolle Das Rebalancing deines Portfolios kostet Geld. In DeFi können Gas-Gebühren dir das Mittagessen wegfressen. Berücksichtige das in deiner Strategie.

3. Liquiditätsprobleme Nicht alle Kryptowährungen sind gleich liquide. Dieser Small-Cap-Altcoin sieht in deiner Optimierung vielleicht super aus, aber versuch mal, ihn während eines Crashs zu verkaufen.

4. Regimewechsel Kryptomärkte haben verschiedene "Regime" - Bullenmärkte, Bärenmärkte, Seitwärtsmärkte. Was in dem einen funktioniert, funktioniert vielleicht nicht im anderen.

Praktische Umsetzungstipps

def practical_portfolio_rebalancing(target_weights, current_weights, threshold=0.05):
    """
    Only rebalance when weights drift beyond threshold
    """
    weight_diff = np.abs(target_weights - current_weights)
    needs_rebalancing = np.any(weight_diff > threshold)

    if needs_rebalancing:
        print("🔄 Rebalancing needed!")
        for i, (target, current) in enumerate(zip(target_weights, current_weights)):
            if abs(target - current) > threshold:
                print(f"Asset {i}: {current:.1%}{target:.1%}")
    else:
        print("✅ Portfolio within tolerance, no rebalancing needed")

    return needs_rebalancing

current_allocation = np.array([0.35, 0.25, 0.15, 0.10, 0.10, 0.05])
target_allocation = max_sharpe_multi.x

practical_portfolio_rebalancing(target_allocation, current_allocation)

Fazit: Dein Toolkit für Portfoliooptimierung

Du hast jetzt ein komplettes Toolkit für die Optimierung von Krypto-Portfolios:

  1. Grundlegende Berechnungen für Risiko und Rendite
  2. Effizienzgrenzen-Visualisierung
  3. Mathematische Optimierung für verschiedene Zielsetzungen
  4. Fortgeschrittene Strategien wie Risikoparität
  5. Backtesting-Framework zur Validierung deiner Strategien
  6. Praktische Überlegungen für die Umsetzung in der realen Welt

Die wichtigsten Erkenntnisse

  • Diversifikation ist ein Free Lunch - das einzige Free Lunch beim Investieren
  • Optimiere entsprechend deiner Risikotoleranz - maximale Sharpe Ratio ist nicht immer das Beste für dich
  • Rebalanciere systematisch, aber übertreibe es nicht mit dem Handeln
  • Bleib bescheiden - Modelle sind Werkzeuge, keine Kristallkugeln
  • Fang einfach an und füge nach und nach Komplexität hinzu

Denk dran: Selbst die besten mathematischen Modelle können in Krypto nicht vorhersagen, wann Elon über Dogecoin twittert oder wann die nächste Börse gehackt wird. Nutze die Portfoliotheorie als Fundament, aber halte immer etwas Pulver trocken und investiere nie mehr, als du dir leisten kannst zu verlieren.

Und jetzt raus mit dir und verantwortungsvoll optimieren! 🚀

Weiterführende Lektüre

Code-Repository

Der gesamte Code aus diesem Tutorial ist auf GitHub verfügbar: https://github.com/suenot/markowitz

Viel Erfolg beim Optimieren! 📈

blog.disclaimer

Authors

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

Dem Markt einen Schritt voraus

Abonniere unseren Newsletter für exklusive KI-Trading-Einblicke, Marktanalysen und Plattform-Updates.

Wir respektieren deine Privatsphäre. Jederzeit abbestellbar.