Hallo & erstmal Danke für eure Antworten!
Ich will mein Vorhaben mal etwas detaillierter beschreiben:
Ich möchte aus meiner Handelsstatistik (Bild Excel 1 ,2 ,3) folgende Daten per Mausklick in ein Word Dokument übertragen:
1: Tag und Uhrzeit (soll ausgelesen werden)
2: Handelsinstrument (immer gleich )
3: Kontraktanzahl ( immer 2 MNQ Kontrakte)
4 Entry: (soll ausgelesen werden)
5 Exit: (soll ausgelesen werden)
6 Gewinn/Verlust (soll ausgelesen werden)
7 Screenshot ( es soll ein .png aus einem "Screenshot Ordner" eingefügt werden zb. nur in diesem Format : 09.09.205 Trade 1
dann kommt ein Word dokument für persönliche Notizen, da schreibe ich details zum Trade rein.
Bild( Word 1 + 2)
Das ganze läuft dann für 3 Trades an einem Tag- das Ganze also mal 3.
Die letzten Probleme waren:
-die Kontrakte immer falsch berechnet wurden. ( die Preise bei "Entry " sind manchmal unterschiedlich)
-die Screenshots konnten nicht gefunden werden trotz richtiger Schreibweise /Pfadeingabe etc.
-meine persönlichen Notizen wurden immer bei starten des "Tradematchers" überschrieben.
Ich hab dann ein paar Fixe mit Powershell gemacht aber kein stabiles Ergebnis mit Chat-gpt erreicht.
Hier sind die Bilder:
https://imgur.com/a/vKdFjGF
Für Hilfe jeglicher Art bei meinem Projekt wäre ich dankbar.
Hier ist der Phyton Code des tradematchers,den ich über eine .bat starte :
# -*- coding: utf-8 -*-
"""
TradeMatcher_Clean.py
Voraussetzungen (einmalig):
pip install pandas python-docx openpyxl
"""
import os, re, glob, unicodedata, datetime as dt
import pandas as pd
from docx import Document
from docx.shared import Pt, Inches
# ======= KONFIG =======
DESKTOP = os.path.normpath(os.path.join(os.environ.get("USERPROFILE",""), "Desktop"))
ATAS_GLOB = os.path.join(DESKTOP, "ATAS_statistics_realtime*.xlsx") # neueste Datei wird genommen
EXPORT_DIR = os.path.join(DESKTOP, "Trade Archiv")
SCREEN_DIR = os.path.join(DESKTOP, "Trades_Phyton") # Screenshot-Ordner (ohne Umlaut)
SECONDS_GROUP = 120 # ±2 Min zu einem Trade zusammenfassen
# ======================
def log(x): print(str(x), flush=True)
def ensure_dir(p): os.makedirs(p, exist_ok=True); return p
# ---- ATAS laden ----
def find_latest_atas(pattern: str) -> str:
files = sorted(glob.glob(pattern), key=os.path.getmtime, reverse=True)
if not files:
raise FileNotFoundError(f"Keine ATAS-Datei gefunden (Muster: {pattern})")
return files[0]
def load_journal(xlsx_path: str) -> pd.DataFrame:
xl = pd.ExcelFile(xlsx_path)
sheet = next((n for n in xl.sheet_names if "ournal" in n.lower()), xl.sheet_names[0])
df = xl.parse(sheet)
for c in ("Open time","Close time"):
if c in df.columns:
df[c] = pd.to_datetime(df[c], errors="coerce")
return df
# ---- Trades gruppieren ----
def coalesce_trades(df: pd.DataFrame, seconds: int = SECONDS_GROUP) -> pd.DataFrame:
if df is None or df.empty: return df
need = ["Instrument","Open time"]
for c in need:
if c not in df.columns:
raise ValueError(f"Spalte fehlt im Journal: {c}")
df = df.sort_values("Open time").reset_index(drop=True)
tol = pd.Timedelta(seconds=seconds)
used=set(); groups=[]
for i,row in df.iterrows():
if i in used: continue
cur=
; used.add(i)
for j in range(i+1, len(df)):
if j in used: continue
r2 = df.iloc[j]
if str(row["Instrument"]) != str(r2["Instrument"]): continue
t1, t2 = row["Open time"], r2["Open time"]
if pd.notna(t1) and pd.notna(t2) and abs(t2 - t1) <= tol:
cur.append(j); used.add(j)
else:
if pd.notna(t1) and pd.notna(t2) and (t2 - t1) > tol:
break
groups.append(cur)
rows=[]
for idxs in groups:
g = df.iloc[idxs]
base = {}
base["Open time"] = pd.to_datetime(g["Open time"]).min()
base["Close time"] = pd.to_datetime(g["Close time"], errors="coerce").max() if "Close time" in g.columns else pd.NaT
base["Instrument"] = str(g["Instrument"].iloc[0])
base["Open price"] = pd.to_numeric(g["Open price"], errors="coerce").iloc[0] if "Open price" in g.columns else pd.NA
base["Close price"]= pd.to_numeric(g["Close price"],errors="coerce").iloc[-1] if "Close price" in g.columns else pd.NA
# KONTRAKTE = MAX(abs(Open volume))
if "Open volume" in g.columns:
contracts = pd.to_numeric(g["Open volume"], errors="coerce").abs().max()
else:
contracts = pd.NA
base["__contracts"] = float(contracts) if (contracts is not pd.NA and pd.notna(contracts)) else pd.NA
# PnL / Ticks summieren
if "PnL" in g.columns:
base["PnL"] = pd.to_numeric(g["PnL"], errors="coerce").fillna(0).sum()
if "Profit (ticks)" in g.columns:
base["Profit (ticks)"] = pd.to_numeric(g["Profit (ticks)"], errors="coerce").fillna(0).sum()
rows.append(base)
out = pd.DataFrame(rows).sort_values("Open time").reset_index(drop=True)
return out
# ---- Screenshot-Finder (rekursiv, Mehrfach-Zuordnung) ----
def _norm(s:str)->str:
s = unicodedata.normalize("NFC", s or "")
return re.sub(r"\s+", " ", s.strip())
def find_screens_for_day(day: dt.date, root: str) -> dict:
"""
Map {trade_nr -> path}. Akzeptiert:
DD.MM, DD.MM.YYYY, YYYY-MM-DD + 'Trade N'
Mehrfach: 'Trade 1 (2 +3)' -> gilt für 1,2,3
"""
mapping={}
if not os.path.isdir(root):
log(f"[SHOT] Ordner fehlt: {root}")
return mapping
dd,mm,yy = day.day, day.month, day.year
pat_date = re.compile(rf"(?:{yy}-{mm:02d}-{dd:02d}|0?{dd}[.\-_/]\s*0?{mm}(?:[.\-_/]\s*{yy})?)", re.I)
pat_ext = re.compile(r"\.(?:png|jpg|jpeg)$", re.I)
pat_main = re.compile(r"trade\s*(\d+)", re.I)
pat_extra= re.compile(r"\(([^)]*)\)")
for dirpath, dirnames, filenames in os.walk(root):
for name in filenames:
if not pat_ext.search(name): continue
n=_norm(name)
if not pat_date.search(n): continue
m=pat_main.search(n)
if not m: continue
nums=[int(m.group(1))]
m2=pat_extra.search(n)
if m2:
for part in re.split(r"[,+\s]+", m2.group(1)):
part=part.strip()
if part.isdigit():
nums.append(int(part))
fpath=os.path.join(dirpath, name)
for no in nums:
mapping.setdefault(no, fpath)
log(f"[SHOT] Zuordnung {day}: {mapping}")
return mapping
# ---- Word-Helfer ----
def add_bold_line(doc, label, value):
p = doc.add_paragraph()
r = p.add_run(f"{label}: ")
r.bold = True
if value is None or (isinstance(value,float) and pd.isna(value)):
p.add_run("–")
else:
p.add_run(str(value))
def add_notes_page_for_trade(doc, trade_nr):
# neue Seite
doc.add_page_break()
# Überschrift
h = doc.add_paragraph()
r = h.add_run(f"Notizen zu Trade {trade_nr}")
r.bold = True
r.font.size = Pt(16)
# Allgemeine Überschrift
p0 = doc.add_paragraph()
r0 = p0.add_run("Erwartungen loslassen")
r0.bold = True
r0.font.size = Pt(12)
doc.add_paragraph() # Leerzeile
def block(label, empty_lines=6):
p = doc.add_paragraph()
rb = p.add_run(f"{label}:")
rb.bold = True
for _ in range(empty_lines):
doc.add_paragraph("")
block("Setup")
block("Struktur/Kontext")
block("Kommentar mit Trademanagement")
block("Emotionaler Stop? Wenn ja warum")
def write_day(doc, df_day: pd.DataFrame, day: dt.date, shots: dict):
section = doc.sections[0]
mg = Pt(24)
section.top_margin = section.bottom_margin = section.left_margin = section.right_margin = mg
doc.add_heading(f"Trade Übersicht – {day.strftime('%Y-%m-%d')}", level=1)
EMU=914400
usable = (section.page_width - section.left_margin - section.right_margin)/EMU
for i,row in df_day.reset_index(drop=True).iterrows():
trade_nr = i+1
doc.add_heading(f"Trade {trade_nr}", level=2)
t = row.get("Open time")
zeit = pd.to_datetime(t).strftime("%d.%m.%Y %H:%M:%S") if pd.notna(t) else "–"
add_bold_line(doc, "
Tag + Uhrzeit", zeit)
add_bold_line(doc, "
Handelsinstrument", row.get("Instrument","–"))
add_bold_line(doc, "
Kontraktanzahl", row.get("__contracts","–"))
add_bold_line(doc, "
Entry", row.get("Open price","–"))
add_bold_line(doc, "
Exit", row.get("Close price","–"))
pnl = row.get("PnL","–"); ticks = row.get("Profit (ticks)","–")
add_bold_line(doc, "
Gewinn/Verlust", f"{pnl} $ ({ticks} Ticks)")
label = f"{day.day:02d}.{day.month:02d} Trade {trade_nr}"
add_bold_line(doc, "
Screenshot", label)
path = shots.get(trade_nr)
if path and os.path.exists(path):
try:
doc.add_picture(path, width=Inches(usable*0.98))
except Exception as e:
doc.add_paragraph(f"(Fehler beim Einfügen des Screenshots: {e})")
else:
doc.add_paragraph("(Kein Screenshot gefunden)")
# direkt danach Notizseite
add_notes_page_for_trade(doc, trade_nr)
def export_day(df_day, day: dt.date, shots: dict) -> str:
doc = Document()
write_day(doc, df_day, day, shots)
ensure_dir(EXPORT_DIR)
out = os.path.join(EXPORT_DIR, f"Trade_Übersicht_{day.strftime('%Y-%m-%d')}.docx")
doc.save(out)
log(f"[OK] {out}")
return out
def main():
ensure_dir(EXPORT_DIR)
ensure_dir(SCREEN_DIR)
xlsx = find_latest_atas(ATAS_GLOB)
log(f"[ATAS] Datei: {xlsx}")
df = load_journal(xlsx)
dfg = coalesce_trades(df, seconds=SECONDS_GROUP)
if dfg.empty:
log("[FAIL] Keine Trades gefunden."); return
dfg["__date__"] = pd.to_datetime(dfg["Open time"]).dt.date
days = sorted([d for d in dfg["__date__"].dropna().unique()])
results=[]
for d in days:
d = d if isinstance(d, dt.date) else d.to_pydatetime().date()
df_day = dfg[dfg["__date__"]==d].copy().reset_index(drop=True)
shots = find_screens_for_day(d, SCREEN_DIR)
results.append(export_day(df_day, d, shots))
log("Fertig.")
for r in results: log(" - " + r)
if __name__ == "__main__":
main()