diff --git a/Dockerfile b/Dockerfile
index 4886e8b..79f53b6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -9,7 +9,7 @@ RUN uv sync --frozen --no-dev
COPY src/ src/
COPY scripts/ scripts/
-COPY strategies.yml portfolios.yml ./
+COPY strategies.yml portfolios.yml VERSION ./
VOLUME /app/data
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..3eefcb9
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+1.0.0
diff --git a/scripts/bump_version.py b/scripts/bump_version.py
new file mode 100644
index 0000000..4179337
--- /dev/null
+++ b/scripts/bump_version.py
@@ -0,0 +1,29 @@
+"""Incrementa la versione (semver) nel file VERSION. Default: patch +1.
+Uso: uv run python scripts/bump_version.py [major|minor|patch] (default patch)
+Stampa la nuova versione. Usato da scripts/deploy.sh ad ogni deploy."""
+import sys
+from pathlib import Path
+
+VF = Path(__file__).resolve().parents[1] / "VERSION"
+
+
+def main():
+ part = sys.argv[1] if len(sys.argv) > 1 else "patch"
+ cur = VF.read_text().strip() if VF.exists() else "0.0.0"
+ try:
+ major, minor, patch = (int(x) for x in cur.split("."))
+ except Exception:
+ major, minor, patch = 0, 0, 0
+ if part == "major":
+ major, minor, patch = major + 1, 0, 0
+ elif part == "minor":
+ minor, patch = minor + 1, 0
+ else:
+ patch += 1
+ new = f"{major}.{minor}.{patch}"
+ VF.write_text(new + "\n")
+ print(new)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
new file mode 100755
index 0000000..66dcc9c
--- /dev/null
+++ b/scripts/deploy.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+# Deploy del paper trader a portafoglio: bumpa la VERSIONE, committa, rebuilda l'immagine e
+# ricrea il container. La versione (es. v1.0.1) compare nei messaggi Telegram -> sai quale
+# codice ha generato quale msg, e aumenta ad OGNI deploy.
+#
+# Uso: ./scripts/deploy.sh [major|minor|patch] (default patch)
+set -euo pipefail
+cd "$(dirname "$0")/.."
+
+PART="${1:-patch}"
+NEW=$(uv run python scripts/bump_version.py "$PART")
+echo ">> nuova versione: v$NEW"
+
+git add VERSION
+git commit -q -m "release: v$NEW" || true
+
+echo ">> rebuild immagine + ricrea container"
+docker compose up -d --build
+
+sleep 8
+docker compose ps --format "{{.Status}}"
+echo ">> deploy v$NEW completato"
diff --git a/scripts/portfolios/hourly_report.py b/scripts/portfolios/hourly_report.py
index a5dd005..20b14b0 100644
--- a/scripts/portfolios/hourly_report.py
+++ b/scripts/portfolios/hourly_report.py
@@ -92,12 +92,16 @@ def build_report() -> str:
r[2] += pnl
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
+ try:
+ ver = (ROOT / "VERSION").read_text().strip()
+ except Exception:
+ ver = "?"
eq = dd = cap = None
if PORT_STATUS.exists():
ps = json.loads(PORT_STATUS.read_text())
eq, cap, dd = ps.get("equity"), ps.get("total_capital"), ps.get("max_dd")
- L = [f"📊 PORT06 — Report orario", now]
+ L = [f"📊 PORT06 — Report orario v{ver}", now]
if eq is not None:
L.append(f"Equity €{eq:.2f} | Cap €{cap:.2f} | maxDD {dd:.3f}%")
diff --git a/src/live/telegram_notifier.py b/src/live/telegram_notifier.py
index 93a8bb2..efa247b 100644
--- a/src/live/telegram_notifier.py
+++ b/src/live/telegram_notifier.py
@@ -6,6 +6,8 @@ import urllib.request
import urllib.parse
import json
+from src.version import APP_VERSION
+
BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "")
CHAT_ID = os.environ.get("TELEGRAM_CHAT_ID", "")
@@ -30,7 +32,7 @@ def send_telegram(text: str) -> bool:
def notify_event(event: str, data: dict | None = None):
if event not in NOTIFY_EVENTS:
return
- lines = [f"📊 {event}"]
+ lines = [f"📊 {event} v{APP_VERSION}"]
if data:
for k, v in data.items():
if k in ("signal",):
diff --git a/src/version.py b/src/version.py
new file mode 100644
index 0000000..fb983c3
--- /dev/null
+++ b/src/version.py
@@ -0,0 +1,18 @@
+"""Versione dell'app, incrementata ad ogni deploy. Compare nei messaggi Telegram per correlare
+i msg al codice in esecuzione. Sorgente: file VERSION nella root (cotto nell'immagine al build).
+Bump: scripts/bump_version.py (o scripts/deploy.sh, che bumpa+committa+rebuilda)."""
+from __future__ import annotations
+
+from pathlib import Path
+
+_VERSION_FILE = Path(__file__).resolve().parents[1] / "VERSION"
+
+
+def get_version() -> str:
+ try:
+ return _VERSION_FILE.read_text().strip()
+ except Exception:
+ return "0.0.0"
+
+
+APP_VERSION = get_version()