Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 33 additions & 18 deletions pytr/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class PPEventType(EventType):
# Swap
"Aufruf von Zwischenpapieren": PPEventType.SWAP,
"Reverse Split": PPEventType.SWAP,
"Tausch": PPEventType.SWAP,
"Teilrückzahlung ohne Reduzierung des Poolfaktors": PPEventType.SWAP,
"Zusammenschluss": PPEventType.SWAP,
# Taxes
Expand Down Expand Up @@ -313,6 +314,14 @@ class PPEventType(EventType):
"Worldline": "FR0011981968",
}

# Known ISIN renames/swaps: old ISIN -> new ISIN.
# Used to resolve paired TR swap events (one event per ISIN) into a single SWAP transaction.
_swap_old_to_new_isin: dict[str, str] = {
"DE0005785604": "DE000FRE5EN2", # Fresenius SE ISIN change 2026-08
"IE000BI8OT95": "LU1781541179", # MSCI World USD (Acc) fund change
"US4385161066": "US4385162056", # Honeywell International reverse split 2026
}

logger = None


Expand Down Expand Up @@ -619,6 +628,7 @@ def from_dict(cls, event_dict: Dict[Any, Any]):
"Aktiensplit",
"Bonusaktien",
"Reverse Split",
"Tausch",
"Teilrückzahlung ohne Reduzierung des Poolfaktors",
"Zusammenschluss",
]
Expand Down Expand Up @@ -682,11 +692,12 @@ def from_dict(cls, event_dict: Dict[Any, Any]):
isin2 = isin
isin = _note_to_isin.get(note, isin2) if note else isin2
elif event_type == PPEventType.SWAP:
if note == "Honeywell International":
isin2 = isin
isin = "US4385161066"
elif note == "MSCI World USD (Acc)" and isin == "LU1781541179":
isin2 = "IE000BI8OT95"
if isin in _swap_old_to_new_isin:
isin2 = _swap_old_to_new_isin[isin]
elif isin in _swap_old_to_new_isin.values():
# Duplicate event for the new ISIN side — suppress it; the old-ISIN event is canonical
event_type = None
ignoreEvent = True
else:
isin2 = (_swap_note_to_isin_overrides.get(note) or _note_to_isin.get(note, note)) if note else None

Expand Down Expand Up @@ -750,19 +761,23 @@ def from_dict(cls, event_dict: Dict[Any, Any]):
elif isin == "LU3170240538":
note = "Apollo"

if event_type is PPEventType.SWAP and uebersicht_dict:
foundentfernt = False
for item in uebersicht_dict.get("data", []):
ititle = item.get("title")
if ititle == "Aktien entfernt":
foundentfernt = True
if not foundentfernt:
event_type = ConditionalEventType.TRADE_INVOICE
isin2 = None
if title == "WORLDLINE S.A. ANR":
title = "Worldline"
isin = "FR0011981968"
note = None
if event_type is PPEventType.SWAP:
if not uebersicht_dict:
event_type = None
ignoreEvent = True
else:
foundentfernt = False
for item in uebersicht_dict.get("data", []):
ititle = item.get("title")
if ititle == "Aktien entfernt":
foundentfernt = True
if not foundentfernt:
event_type = ConditionalEventType.TRADE_INVOICE
isin2 = None
if title == "WORLDLINE S.A. ANR":
title = "Worldline"
isin = "FR0011981968"
note = None

if (
subtitle == "Zusammenschluss"
Expand Down
48 changes: 48 additions & 0 deletions tests/events/tausch_informative.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"id": "bbf2affb-30ab-45bd-a7d6-d3047360e905",
"timestamp": "2025-11-04T08:59:35.225+0000",
"title": "L'Oreal",
"icon": "logos/FR0000120321/v2",
"subtitle": "Tausch",
"action": {
"type": "timelineDetail",
"payload": "bbf2affb-30ab-45bd-a7d6-d3047360e905"
},
"source": "timelineActivity",
"details": {
"id": "bbf2affb-30ab-45bd-a7d6-d3047360e905",
"sections": [
{
"title": "Du hast eine Kapitalmaßnahme erhalten",
"data": {
"icon": "logos/FR0000120321/v2",
"timestamp": "2025-11-04T08:59:35.225Z",
"status": "executed"
},
"type": "header"
},
{
"title": "Information",
"text": "Das beigefügte Dokument enthält wichtige Informationen zu deiner L'Oreal-Investition. Bitte überprüfe das Dokument.",
"type": "text"
},
{
"title": "Dokumente",
"data": [
{
"title": "Kapitalmaßnahmen",
"detail": "04.11.2025",
"action": {
"payload": "",
"type": "browserModal"
},
"id": "e68a0462-3569-4eea-a33c-f5b10154986a",
"postboxType": "CA_GENERIC_OPTIONS_NOTIFICATION"
}
],
"type": "documents"
}
]
},
"eventType": "SSP_CORPORATE_ACTION_INFORMATIVE"
}
124 changes: 124 additions & 0 deletions tests/events/tausch_new_isin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
"id": "cb25d019-05f3-3a6c-8785-e410b70df9cd",
"timestamp": "2026-08-13T15:22:52.025+0000",
"title": "Fresenius SE & Co. KGaA Namens-Aktien o.N.",
"icon": "logos/DE000FRE5EN2/v2",
"subtitle": "Tausch",
"action": {
"type": "timelineDetail",
"payload": "cb25d019-05f3-3a6c-8785-e410b70df9cd"
},
"trailing": null,
"eventType": "SSP_CORPORATE_ACTION_NO_CASH",
"hidden": false,
"deleted": false,
"source": "timelineActivity",
"details": {
"id": "cb25d019-05f3-3a6c-8785-e410b70df9cd",
"sections": [
{
"title": "Deine Aktien waren von einer Kapitalmaßnahme betroffen",
"data": {
"icon": {
"asset": "logos/DE000FRE5EN2/v2",
"badge": null
},
"subtitleText": "13 Aug. · 15:22",
"status": "executed"
},
"type": "header"
},
{
"title": "Übersicht",
"data": [
{
"title": "Status",
"detail": {
"text": "Ausgeführt",
"functionalStyle": "EXECUTED",
"type": "status"
},
"style": "plain"
},
{
"title": "Orderart",
"detail": {
"text": "Tausch",
"displayValue": {
"text": "Tausch",
"textDataSensitivity": "PUBLIC"
},
"type": "text"
},
"style": "plain"
},
{
"title": "Wertpapier",
"detail": {
"text": "Fresenius",
"displayValue": {
"text": "Fresenius",
"textDataSensitivity": "PUBLIC"
},
"type": "text"
},
"style": "plain"
},
{
"title": "Aktien entfernt",
"detail": {
"text": "5.431472",
"displayValue": {
"text": "5.431472",
"textDataSensitivity": "PUBLIC"
},
"type": "text"
},
"style": "plain"
},
{
"title": "Wertpapier",
"detail": {
"text": "Fresenius SE & Co. KGaA Namens-Aktien o.N.",
"displayValue": {
"text": "Fresenius SE & Co. KGaA Namens-Aktien o.N.",
"textDataSensitivity": "PUBLIC"
},
"type": "text"
},
"style": "plain"
},
{
"title": "Aktien hinzugefügt",
"detail": {
"text": "5.431472",
"displayValue": {
"text": "5.431472",
"textDataSensitivity": "PUBLIC"
},
"type": "text"
},
"style": "plain"
}
],
"type": "table"
},
{
"title": "Dokumente",
"data": [
{
"title": "Dokumente",
"detail": "13.08.2026",
"action": {
"payload": "https://example.com/document.pdf",
"type": "browserModal"
},
"id": "5310c3d8-e7b5-4ad7-97fb-a48b39f5f579",
"postboxType": "CA_SECURITIES_INVOICE"
}
],
"type": "documents"
}
]
}
}
124 changes: 124 additions & 0 deletions tests/events/tausch_old_isin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
"id": "d569e3ae-4a62-3bda-9798-4b21ff0a5820",
"timestamp": "2026-08-13T15:22:52.025+0000",
"title": "Fresenius",
"icon": "logos/DE0005785604/v2",
"subtitle": "Tausch",
"action": {
"type": "timelineDetail",
"payload": "d569e3ae-4a62-3bda-9798-4b21ff0a5820"
},
"trailing": null,
"eventType": "SSP_CORPORATE_ACTION_NO_CASH",
"hidden": false,
"deleted": false,
"source": "timelineActivity",
"details": {
"id": "d569e3ae-4a62-3bda-9798-4b21ff0a5820",
"sections": [
{
"title": "Deine Aktien waren von einer Kapitalmaßnahme betroffen",
"data": {
"icon": {
"asset": "logos/DE0005785604/v2",
"badge": null
},
"subtitleText": "13 Aug. · 15:22",
"status": "executed"
},
"type": "header"
},
{
"title": "Übersicht",
"data": [
{
"title": "Status",
"detail": {
"text": "Ausgeführt",
"functionalStyle": "EXECUTED",
"type": "status"
},
"style": "plain"
},
{
"title": "Orderart",
"detail": {
"text": "Tausch",
"displayValue": {
"text": "Tausch",
"textDataSensitivity": "PUBLIC"
},
"type": "text"
},
"style": "plain"
},
{
"title": "Wertpapier",
"detail": {
"text": "Fresenius",
"displayValue": {
"text": "Fresenius",
"textDataSensitivity": "PUBLIC"
},
"type": "text"
},
"style": "plain"
},
{
"title": "Aktien entfernt",
"detail": {
"text": "5.431472",
"displayValue": {
"text": "5.431472",
"textDataSensitivity": "PUBLIC"
},
"type": "text"
},
"style": "plain"
},
{
"title": "Wertpapier",
"detail": {
"text": "Fresenius SE & Co. KGaA Namens-Aktien o.N.",
"displayValue": {
"text": "Fresenius SE & Co. KGaA Namens-Aktien o.N.",
"textDataSensitivity": "PUBLIC"
},
"type": "text"
},
"style": "plain"
},
{
"title": "Aktien hinzugefügt",
"detail": {
"text": "5.431472",
"displayValue": {
"text": "5.431472",
"textDataSensitivity": "PUBLIC"
},
"type": "text"
},
"style": "plain"
}
],
"type": "table"
},
{
"title": "Dokumente",
"data": [
{
"title": "Dokumente",
"detail": "13.08.2026",
"action": {
"payload": "https://example.com/document.pdf",
"type": "browserModal"
},
"id": "22b5d029-0f5c-46ad-b07f-c5ad0ae11ee2",
"postboxType": "CA_SECURITIES_INVOICE"
}
],
"type": "documents"
}
]
}
}
Loading