Aktywne Wpisy

Pulpetito +474
#lewandowski Robert przeżywa trudne chwile w Chicago, gdzie jest zupełnie sam w nowym środowisku a Anka lata razem z Luisem do Turcji na zawody z w-fu. Smutne. Ciekawe k---a z kim dzieci siedzą przez te dni.
źródło: lewa1
Pobierz
Let_Me_2_Be +415
#lekarz100k #konowalposting z okazji zbliżającego się święta wojska Polskiego przypomniało mi się jak ludzie wpłacali pieniądze na owdowiałą panią lekarz po śmierci pilota Macieja „Slab” Krakowiana. Poniżej tylko jedna ze zbiórek.
źródło: obraz
Pobierz




Wrzucam poniżej skrypt Python importu operacji gotówkowych na rachunku z XTB do Portfolio Performance w wersji 2.1
Zmiany wobec wersji 2.0:
- Brak konieczności zmiany nazwy pliku .xlsx z XTB. Wrzucasz skrypcik do folderku z wyeksportowanym (nowym) raportem z XTB i hula od strzała
- W związku z powyższym eksport zdarzeń nietypowych został zmieniony z plików .xlsx do .csv
- Skrypt teraz uwzględnia liczbę posiadanych udziałów aktywów wypłacających dywidendę i wylicza dywidendę za udział
Poniższy skrypcik zapisujemy do pliku z rozszerzeniem .py albo .ipynb i odpalamy sobie w Pythonie (zobacz jak)
import glob
import pandas as pd
# Import excela z XTB
import warnings
warnings.filterwarnings('ignore', message='Workbook contains no default style')
file_name = glob.glob('*.xlsx')[0]
df = pd.read_excel(file_name, sheet_name='Cash Operations', skiprows=4)
df['Time'] = pd.to_datetime(df['Time'])
df['Day'] = df['Time'].dt.normalize()
# Detekcja nietypowych zdarzeń (corr) potencjalnie wymagających ręcznych korekt
corr = df[df['Comment'].str.contains('corr', case=False, na=False)]
if not(corr.empty):
corr.to_csv('XTB_corr.csv')
# Cleanup
df = df[df['Type'] != 'Total']
df = df.sort_values(by='ID').reset_index(drop=True)
df['Shares'] = pd.to_numeric( df['Comment'].str.extract(r'([0-9]+(?:/[0-9]+)?)\s*@')[0].str.split('/').str[0], errors='coerce')
df['Price'] = pd.to_numeric( df['Comment'].str.extract(r'@\s*([0-9]*\.?[0-9]+)')[0], errors='coerce' )
df['Shares_div'] = pd.to_numeric( df['Comment'].str.extract(r"PLN\s+([\d.]+)")[0], errors='coerce')
df['Shares_div'] = df['Amount'] / df['Shares_div']
# Detekcja transakcji w walucie innej niż waluta rachunku
tr = df[ df['Type'].isin(['Stock purchase', 'Stock sell'])].copy()
tr['Amount_check'] = (tr['Shares'] * tr['Price']).round(2)
fx_tr = tr[ (tr['Amount'].abs() - tr['Amount_check']).abs() > 0.02 ]
if not(fx_tr.empty):
fx_tr.to_csv('XTB_fx_tr.csv')
df['Gross Amount'] = float('nan')
df['Exchange Rate'] = float('nan')
df.loc[fx_tr.index, 'Gross Amount'] = ( df.loc[fx_tr.index, 'Shares'] * df.loc[fx_tr.index, 'Price'] ).round(2)
df.loc[fx_tr.index, 'Exchange Rate'] = ( df.loc[fx_tr.index, 'Amount'].abs() / df.loc[fx_tr.index, 'Gross Amount'] )
df = df.drop(columns=['ID', 'Product', 'Comment'])
# Przypisanie podatków od odsetek do wiersza z odsetkami
df['Taxes'] = float('nan')
ffi = ( df[df['Type'] == 'Free funds interest'].sort_values('Time').copy() )
ffi_tax = ( df[df['Type'] == 'Free funds interest tax'][['Time', 'Amount']].sort_values('Time').rename(columns={'Amount': 'Taxes'}) )
ffi = pd.merge_asof( ffi, ffi_tax, on='Time', direction='nearest', tolerance=pd.Timedelta('1D'), suffixes=('', '_new') )
ffi['Taxes'] = ffi['Taxes_new']
ffi = ffi.drop(columns='Taxes_new')
ffi['Amount'] = ffi['Amount'] + ffi['Taxes'].fillna(0)
# Agregacja dywidend do 1 płatności na instrument dziennie, przypisanie podatku od dywidend do wiersza z dywidendami
div = ( df[df['Type'] == 'Dividend'].groupby(['Day', 'Ticker'], as_index=False).agg({'Time': 'first', 'Type': 'first', 'Amount': 'sum', 'Shares_div': 'sum'}) )
wht = ( df[df['Type'] == 'Withholding tax'].groupby(['Day', 'Ticker'], as_index=False)['Amount'].sum().rename(columns={'Amount': 'Taxes'}) )
div = div.merge(wht, on=['Day', 'Ticker'], how='left')
div['Amount'] = div['Amount'] + div['Taxes'].fillna(0)
div['Shares'] = div['Shares_div']
# Usuń zbędne oryginalne wiersze
df = df[ ~df['Type'].isin([ 'Dividend', 'Withholding tax', 'Free funds interest', 'Free funds interest tax']) ]
# Połącz z wcześniej przetworzonymi wierszami o odsetkach i dywidendach
df = (pd.concat([df, div, ffi], ignore_index=True).sort_values('Time').reset_index(drop=True))
df['Taxes'] = (-1)*df['Taxes']
# Yahoo Finance compatible endings
df['Ticker'] = df['Ticker'].str.replace('.PL', '.WA', regex=False)
df['Ticker'] = df['Ticker'].str.replace('.UK', '.L', regex=False)
df['Ticker'] = df['Ticker'].str.replace('.US', '', regex=False)
df['Ticker'] = df['Ticker'].str.replace('.FR', '.PA', regex=False)
df['Time'] = df['Time'].dt.strftime('%Y-%m-%dT%H:%M')
# Format to PP-importable csv (Polish)
df = df.rename(columns={
'Time': 'Data',
'Type': 'Typ',
'Taxes': 'Podatki',
'Shares': 'Akcje',
'Amount': 'Wartość',
'Gross Amount': 'Kwota brutto',
'Exchange Rate': 'Kurs wymiany',
'Ticker': 'Symbol giełdowy waloru',
'Instrument': 'Nazwa waloru'
})
df['Typ'] = df['Typ'].replace({
'Stock purchase': 'Kupno',
'Stock sell': 'Sprzedaj',
'Deposit': 'Depozyt',
'Withdrawal': 'Wypłata',
'Dividend': 'Dywidenda',
'Free funds interest': 'Odsetki',
'Custody fee': 'Opłaty'
})
# Treat eWallet transfers as deposits or withdrawals
df.loc[ (df['Typ'] == 'Transfer') & (df['Wartość'] > 0), 'Typ' ] = 'Depozyt'
df.loc[ (df['Typ'] == 'Transfer') & (df['Wartość'] < 0), 'Typ' ] = 'Wypłata'
# Reorder columns
df = df[ ['Data', 'Typ', 'Wartość', 'Kwota brutto', 'Kurs wymiany', 'Podatki', 'Akcje', 'Symbol giełdowy waloru'] ]
# Export to csv
df.to_csv('XTB_to_PP.csv', index=False, sep=';', decimal=',')
# Efekt końcowy
df
źródło: Zrzut ekranu 2026-07-4 o 13.55.11
Pobierzźródło: image
Pobierz