I was bored but also am interested in the idea someone mentioned ( @Your_Full_Name on the @cubanpete_the_swiss thread?) of having a mechanical strategy of swiss dividend companies.
So I though “why not asking AI to write down a starting point?”, and after a few iterations here is the result (Note: I could have told it to download the CSV automatically but it failed a couple of times so I thought to start with the file already there. You can get the CSV here: https://www.ishares.com/ch/individual/en/products/264108/ishares-swiss-dividend-ch-fund )
Next steps? I didn’t really check the strategies there other than seeing that the ranking isn’t that well made.
import pandas as pd
import yfinance as yf
import os
# ---------------------------------------------
# Global variables
# ---------------------------------------------
HOLDINGS_FILE = "CHDVD_holdings.csv"
FACTORS_FILE = "CHDVD_with_factors.csv"
skip_tickers = {"CHF", "F-GSI", "GBP","SMZ5"}
factor_columns = [
"dividend_yield", "pe_ratio", "pb_ratio", "market_cap",
"roe", "roa", "profit_margin", "debt_to_equity"
]
# ---------------------------------------------
# Function to create CHDVD_with_factors.csv
# ---------------------------------------------
def create_factors_file():
if not os.path.exists(HOLDINGS_FILE):
print(f"⚠ {HOLDINGS_FILE} not found. Please download and prepare it first.")
return None
df = pd.read_csv(HOLDINGS_FILE)
ticker_col = df.columns[0]
# Assume the second column is company name
name_col = df.columns[1] if len(df.columns) > 1 else None
# Remove ignored tickers
df = df[~df[ticker_col].isin(skip_tickers)].reset_index(drop=True)
# Add Yahoo Finance ticker column
df["yf_ticker"] = df[ticker_col].astype(str) + ".SW"
for col in factor_columns:
df[col] = None
print("\nFetching factor data from yfinance...\n")
for idx, row in df.iterrows():
yf_ticker = row["yf_ticker"]
try:
info = yf.Ticker(yf_ticker).info
df.loc[idx, "dividend_yield"] = info.get("dividendYield")
df.loc[idx, "pe_ratio"] = info.get("trailingPE")
df.loc[idx, "pb_ratio"] = info.get("priceToBook")
df.loc[idx, "market_cap"] = info.get("marketCap")
df.loc[idx, "roe"] = info.get("returnOnEquity")
df.loc[idx, "roa"] = info.get("returnOnAssets")
df.loc[idx, "profit_margin"] = info.get("profitMargins")
df.loc[idx, "debt_to_equity"] = info.get("debtToEquity")
print(f"✔ Retrieved data for {yf_ticker} ({row[name_col]})")
except Exception as e:
print(f"⚠ Failed for {yf_ticker} ({row[name_col]}): {e}")
df.to_csv(FACTORS_FILE, index=False)
print(f"\nSaved enriched data to: {FACTORS_FILE}\n")
return df
# ---------------------------------------------
# Functions for scoring
# ---------------------------------------------
def dividend_scoring(df):
name_col = df.columns[1]
df["score_dividend"] = df["dividend_yield"].rank(ascending=False)
print(df[[df.columns[0], name_col, "dividend_yield", "score_dividend"]])
return df
def value_scoring(df):
name_col = df.columns[1]
df["score_value"] = df["pe_ratio"].rank(ascending=True) + df["pb_ratio"].rank(ascending=True)
print(df[[df.columns[0], name_col, "pe_ratio", "pb_ratio", "score_value"]])
return df
def quality_scoring(df):
name_col = df.columns[1]
df["score_quality"] = df["roe"].rank(ascending=False) + df["roa"].rank(ascending=False) + df["profit_margin"].rank(ascending=False) + df["debt_to_equity"].rank(ascending=True)
print(df[[df.columns[0], name_col, "roe", "roa", "profit_margin", "debt_to_equity", "score_quality"]])
return df
def momentum_scoring(df):
name_col = df.columns[1]
print("Momentum scoring not implemented yet (requires historical prices).")
return df
def risk_scoring(df):
name_col = df.columns[1]
print("Risk scoring not implemented yet (requires historical prices).")
return df
def composite_scoring(df):
name_col = df.columns[1]
for col in ["score_dividend", "score_value", "score_quality"]:
if col not in df.columns:
print(f"⚠ {col} not found, run the individual scoring first.")
return df
df["score_composite"] = df["score_dividend"] + df["score_value"] + df["score_quality"]
print(df[[df.columns[0], name_col, "score_composite"]].sort_values("score_composite"))
return df
# ---------------------------------------------
# Menu
# ---------------------------------------------
def menu():
while True:
print("\n==== CHDVD Scoring Menu ====")
if not os.path.exists(HOLDINGS_FILE):
print(f"⚠ {HOLDINGS_FILE} not found. Please download and prepare it first.")
else:
print(f"{HOLDINGS_FILE} found ✅")
if os.path.exists(FACTORS_FILE):
print(f"{FACTORS_FILE} found ✅")
df = pd.read_csv(FACTORS_FILE)
else:
print(f"{FACTORS_FILE} not found. Press 1 to create it.")
df = None
print("\nMenu:")
print("1 - Create CHDVD_with_factors.csv (fetch factors)")
print("2 - Dividend scoring")
print("3 - Value scoring")
print("4 - Quality scoring")
print("5 - Momentum scoring")
print("6 - Risk scoring")
print("7 - Composite scoring")
print("0 - Exit")
choice = input("Enter choice: ").strip()
if choice == "0":
break
elif choice == "1":
df = create_factors_file()
elif choice == "2" and df is not None:
df = dividend_scoring(df)
elif choice == "3" and df is not None:
df = value_scoring(df)
elif choice == "4" and df is not None:
df = quality_scoring(df)
elif choice == "5" and df is not None:
df = momentum_scoring(df)
elif choice == "6" and df is not None:
df = risk_scoring(df)
elif choice == "7" and df is not None:
df = composite_scoring(df)
else:
print("Invalid choice or CHDVD_with_factors.csv not available. Run option 1 first.")
# ---------------------------------------------
# Run menu
# ---------------------------------------------
if __name__ == "__main__":
menu()
Admins: Feel free to move it to “coffe” if it’s too frivoulous ![]()