Zum Inhalt springen
t4ri > Algotrading > Algo-Trading “Top 5” Strategie

Algo-Trading “Top 5” Strategie

unter “Aktien für den Optionshandel finden” hatten wir erläutert, wie man mit finviz für den Optionshandel geeignete Aktien finden kann. Ein weitere Auswahlstrategie, die mit finviz nicht parametrierbar ist, bietet die folgende Vorgehensweise, die mit Algo-Trading realisiert werden kann (bitte beachte auch hier die Risikohinweise). Wir suchen hierzu Aktien, die folgende Bedingungen erfüllen:

  • wir suchen Aktien aus dem S&P500, die mindestens historische Kurse über 3 Jahre vorweisen
  • die gesuchten Aktien sollen im aktuellen Monat, in den zurückliegenden 5 Jahren möglichst keinen negativen Trend aufweisen
  • der maximale Kursrückgang im betrachteten Monat sollte einen definierten Prozentwert nicht überschreiten
  • das aktuelle Optionskontrakt Handelsvolumen sollte hoch sein
  • als konkretere Ziele können wir z.B. ergänzen: mindestens 80% positiver Trend in den letzten Jahren, Kursrückgang nicht unter -5%, Kursanstieg > 10%, Handelsvolumen > 1000 Kontrakte

Die Strategie ist es hierbei, die Aktien zu finden, die gemäß ihrem historischen Trend die o.g. Anforderungen erfüllen, mit der Hoffnung, dass diese auch in diesem Jahr ein ähnlich positives Verhalten aufzeigen. Mittels eines Bull Put Spread oder Bull Call Spread können dann verlustbegrenzt zu diesen Aktien Optionen gehandelt werden. Idealerweise sollte die Option in der letzten Woche des Vormonats erworben werden.

Als Grundlage zum Thema Python Programmierung der Verweis auf unseren Einführungsbeitrag zu diesem Thema.

Der folgende Python Code ermittelt uns die notwendigen Daten. Die Funktion getData() übernimmt hierbei die Datenermittlung. Sie prüft zunächst ob bereits eine gespeicherte Auswertung vorliegt, bzw. wiederholt diese, wenn die letzte Auswertung mehr als 330 Tage zurück liegt.
Die Funktion get_sp500_tickers() bestimmt die aktuellen Ticker-Symbole des S&P500. Im weiteren Ablauf werden dann über die Funktion check_stock_performance() die Performance-Werte (Erfolgsrate %, Max. Verlust %, Max. Gewinn %, mittlere Rendite %) und über check_option_volume() das aktuelle Options Kontraktvolumen bestimmt. Final wird das Ergebnis in einer CSV-Tabelle gespeichert, d.h. eine weitere Auswertung mit Excel wäre ebenfalls möglich.

import os
import yfinance as yf
import logging
import pandas as pd
from datetime import date, datetime, timedelta

# Liste der Aktien, die analysiert werden sollen
database = 'stockPerformance.csv'
df = pd.DataFrame()

# Funktion zum Abrufen der S&P 500 Liste
def get_sp500_tickers():
    url = 'https://en.wikipedia.org/wiki/List_of_S%26P_500_companies'
    table = pd.read_html(url)
    df = table[0]
    return df['Symbol'].tolist()

# Bestimmung der Performance Werte
def check_stock_performance(ticker):
    # 5 Jahre Kursdaten von yahoo einlsesen
    years = 5
    try:
        stock = yf.Ticker(ticker)
        data = stock.history(period=str(years)+"y", interval="1d")    
    except:
        return None
    
    if data.empty:
        return None
    
    end_date = datetime.today()
    start_date = end_date - timedelta(days=years*365)  # 5 Jahre zurück
    results = {}

    # Performancedaten pro Monat bestimmen
    for mo in range(1,13):
        positive_years = 0
        total_years = years
        max_loss = None
        max_win = None 
        mwin = 0
        # jeder zurückliegende Jahr betrachten
        for year in range(years):
            year_data = data[(data.index.month == mo) & (data.index.year == (end_date.year - 1 - year))]
            if year_data.empty:
                total_years -= 1
                continue

            # Verluste und Gewinne bestimmen
            start_price = year_data.iloc[0]['Open']
            end_price = year_data.iloc[-1]['Close']
            min_price = year_data['Low'].min()
            max_price = year_data['High'].max()
            
            if (end_price > start_price):
                positive_years += 1
            loss = (min_price - start_price) / start_price
            win = (max_price - start_price) / start_price
            mwin += (end_price - start_price) / start_price
            if max_loss == None or loss < max_loss:
                max_loss = loss
            if max_win == None or win > max_win:
                max_win = win
            
        if total_years < 3:  # Mindestens 3 Jahre müssen Daten vorhanden sein
            continue

        # das Ergebnis ablegen
        perfValue = (positive_years / total_years)    
        results[mo] = (max_loss,max_win,mwin/total_years,perfValue)
    return results

# Bestimmung des Options Handelsvolumens
def check_option_volume(ticker):
    try:
        stock = yf.Ticker(ticker)
        options = stock.options
        # aktuellen Kontrakt bestimmen
        if len(options) > 0:
            option_chain = stock.option_chain(options[0])
        else:
            return None
    except:
        return None
    
    if not options:
        return None

    # Volumen des aktuellsten Kontrakts
    total_volume = option_chain.calls['volume'].sum() + option_chain.puts['volume'].sum()

    return total_volume

def getData():
    global database,df

    # wenn nicht älter als 330 Tage csv einlesen
    if os.path.exists(database):
        c_time = os.path.getmtime(database)
        dt = datetime.fromtimestamp(c_time).date()
        agedays = int((date.today()-dt) / timedelta(days=1))
        if agedays < 330:
            df = pd.read_csv(database)  
            return

    # Datenaktualisierung starten
    sp500_tickers = get_sp500_tickers()
    # yf trace deaktivieren
    logger = logging.getLogger('yfinance')
    logger.disabled = True
    logger.propagate = False
    
    # performance Daten bestimmen
    data=[]
    stockdata = {}
    for stock in sp500_tickers:    
        results = check_stock_performance(stock)
        if results == None:
            continue
        vol = check_option_volume(stock) 
        print(stock)
        for mo in range(1,13):    
            if mo in results:
                (maxloss,maxwin,mwin,perfValue) = results[mo]
                stockdata["Aktie"] = stock
                stockdata["Erfolgsrate %"] = round(perfValue * 100.0,2)
                stockdata["Max. Verlust %"] = round(maxloss * 100.0,2)
                stockdata["Max. Gewinn %"] = round(maxwin * 100.0,2)
                stockdata["Mtl. Rendite %"] = round(mwin * 100.0,2)
                stockdata["Volumen"] = vol  
                stockdata["Monat"] = mo                  
                data.append({**stockdata})
                
    # Speicherung in CSV Datei    
    df = pd.DataFrame(data).sort_values(by=['Monat','Erfolgsrate %','Max. Verlust %','Volumen'], ascending=False)
    df.to_csv(database, index=False) 

# Ausgabe der Top Aktien
def getBestofMonth(month):
    global df

    dfm = df[df['Monat'] == month]
    print(dfm.head())

# main
getData()
month = datetime.now().month
getBestofMonth(month)
getBestofMonth(month%12+1)

Die Funktion getBestofMonth() liefert uns die Top 5 Aktien für den aktuellen und den nächsten Monat, sortiert nach Erfolgsrate und Max. Verlust.

Gemäß dieser Auswertung können wir nun entscheiden, ob wir auf Grund des möglichen max. Verlust eher kein Risiko eingehen wollen, d.h. nicht handeln, oder welche Strikelevel wir für eine Option setzen möchten. Als Zieltermin für die Laufzeit der Optionen sollten wir das Monatsende wählen.

Als Options-Strategie eignen sich der Bull Call Spreads für Positionen, für die eine Kursteigerung wahrscheinlich ist. Spreads sind insofern attraktiv, da sie ein begrenztes Verlustrisiko aufweisen, aber der Bull Call Spread ist nicht geeignet, wenn sich der Kurs nur seitwärts oder abwärts bewegen sollte. Als Zielkurs für den Strikepreis von Call Kauf und Verkauf könnte man den “max. Kursverlust %” wählen. Zum Beispiel bei einem aktuellen Kurs 100$ und -5% max. Kursverlust, dann Call Verkauf zum Basispreis 105$ und Call Kauf zum Basispreis 95$. Der max. Verlust ergibt sich aus Prämie Call Verkauf – Prämie Call Kauf, wenn beide Optionen verfallen, d.h. der Aktienkurs unter den unteren (Long Call) Strikepreis fällt. Eine Gewinnmitnahme ist denkbar, wenn die Aktien-Kurssteigerung die mittlere Kurssteigerung und der Kurs den oberen Strikepreis überschritten hat.

Als weitere Options-Strategie der Bull Put Spread für Positionen, für die eine Kursteigerung oder Seitwärtsbewegung wahrscheinlich ist. Verkauf einer Put-Option mit höherem Strike-Preis (im Beispiel oben 105$) und Kauf einer Put-Option mit niedrigerem Strike-Preis (im Beispiel oben 95$). Der max. Verlust ergibt sich aus Prämie Put Verkauf – Strikepreis-Differenz * 100 (im Beispiel ist die Strikepreis-Differenz 10$).

Hier nun eine Auswertung auf Basis des oben gezeigten Python Codes:

Favorisierte Aktien für den Monat März

AktieErfolgsrate %Max. Verlust %Max. Gewinn %Mtl. Rendite %VolumenMonat
KR100.0-3.930.0513.520573.03
CEG100.0-4.0129.513.363645.03
WMT100.0-5.219.035.4824139.03
CARR100.0-5.6843.7513.47395.03
GILD100.0-7.5523.394.051103.03