Provider-Failover bei hartem Fehlschlag + Einsatz-Prozentfeld im Dashboard
1) LLM-Failover (core/agent.py): ein hart gescheiterter Provider wird zeitweise uebersprungen, analyze() nimmt den naechsten aus der Kette. Hart = 401/402/403/ 404 (Key/Guthaben/Modell) -> 30 min, nicht erreichbar -> 5 min. Timeout/429/5xx loesen BEWUSST keinen Wechsel aus (voruebergehend; sonst kostet jede Lastspitze die volle Timeout-Summe aller Anbieter). Neu im Snapshot: agent.provider_dead mit Restminuten - der DeepSeek-Ausfall stand vorher nur im Log und blieb deshalb 18 h unbemerkt. 9 Szenarien getestet. 2) Einsatz-Prozentfeld (web, v=137): margin_buffer_pct hatte bisher keine UI. Neues Feld "Einsatz %" neben "Einsatz EUR", POST /api/marginpct -> engine.set_margin_pct -> config.set_margin_buffer, Snapshot margin_pct, neustart-fest. Der feste EUR-Betrag hat Vorrang; das Prozentfeld wird dann ausgegraut, damit nicht unklar bleibt was gilt. Auf 1-99 % geklemmt. Ende-zu-Ende getestet (50, 150->99, 0 und -5 abgelehnt, 95, persistiert). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7e9b0196a5
commit
cc4f1a0863
+54
@@ -908,6 +908,24 @@ function render(d) {
|
||||
mgi.value = mm > 0 ? String(mm) : "";
|
||||
mgi.classList.toggle("on", mm > 0);
|
||||
}
|
||||
// Einsatz in Prozent der freien Margin. Ausgegraut, sobald links ein fester
|
||||
// Betrag steht — der hat Vorrang, und ohne den Hinweis wäre unklar, was gilt.
|
||||
const mpi = $("marginpct-input");
|
||||
if (mpi && document.activeElement !== mpi) {
|
||||
const mp = d.margin_pct || 0;
|
||||
mpi.value = mp > 0 ? String(mp) : "";
|
||||
const fest = (d.manual_margin || 0) > 0;
|
||||
mpi.classList.toggle("on", mp > 0 && !fest);
|
||||
const wrap = $("marginpct-wrap");
|
||||
if (wrap) {
|
||||
wrap.classList.toggle("muted", fest);
|
||||
wrap.title = fest
|
||||
? `Ohne Wirkung: links steht ein fester Einsatz (${fmt(d.manual_margin, 2)} €). `
|
||||
+ `Der Prozentsatz (${mp} %) bleibt nur die Obergrenze.`
|
||||
: "Einsatz als Prozent der freien Margin (1–99). "
|
||||
+ "Greift, solange links kein fester Betrag steht.";
|
||||
}
|
||||
}
|
||||
// Einblendung: der Bot hat am S/R automatisch geschlossen (Zähler stieg)
|
||||
const src = d.sr_close_count;
|
||||
if (src != null) {
|
||||
@@ -1307,6 +1325,42 @@ async function setManualMargin() {
|
||||
});
|
||||
})();
|
||||
|
||||
// Einsatz in PROZENT der freien Margin (User-Wunsch 2026-08-05) — das Gegenstück
|
||||
// zum festen Betrag oben. Steuert `margin_buffer_pct`, das bisher nur in der ini
|
||||
// stand. ⚠ Ein gesetzter fester Betrag hat Vorrang; darauf weist der Toast hin.
|
||||
async function setMarginPct() {
|
||||
const el = $("marginpct-input"); if (!el) return;
|
||||
const v = parseFloat(el.value);
|
||||
if (isNaN(v) || v < 1 || v > 99) {
|
||||
toast("Bitte 1–99 % eingeben (100 % ließe keinen Puffer für Spread/Swap)", false);
|
||||
return;
|
||||
}
|
||||
const tok = await ensureToken();
|
||||
if (tok === null) return;
|
||||
el.blur();
|
||||
try {
|
||||
const r = await fetch("api/marginpct", { method: "POST",
|
||||
headers: { "X-Auth-Token": tok, "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ value: v }) });
|
||||
if (r.status === 401) { clearToken(); throw new Error("401"); }
|
||||
const j = await r.json();
|
||||
if (j.ok === false) { toast(j.error || "abgelehnt", false); return; }
|
||||
const fest = parseFloat(($("margin-input") || {}).value || "0") > 0;
|
||||
toast(`Einsatz: ${fmt(j.value ?? v, 0)} % der freien Margin`
|
||||
+ (fest ? " — greift erst, wenn der feste Betrag links leer ist" : ""), true);
|
||||
} catch (e) {
|
||||
toast(e.message === "401" ? "Token abgelaufen — neu eingeben" : "Netzwerkfehler", false);
|
||||
}
|
||||
}
|
||||
(() => {
|
||||
const el = $("marginpct-input");
|
||||
if (!el) return; // null-sicher (Cache-Regel)
|
||||
el.addEventListener("change", setMarginPct);
|
||||
el.addEventListener("keydown", e => {
|
||||
if (e.key === "Enter") { e.preventDefault(); e.target.blur(); }
|
||||
});
|
||||
})();
|
||||
|
||||
// Notfall-Stop: manueller Verlust-Wert, bei dem der Server sofort schließt.
|
||||
// Wieder eingeblendet 2026-07-22 (Backend/Persistenz waren die ganze Zeit aktiv).
|
||||
async function setEmg() {
|
||||
|
||||
+11
-4
@@ -6,7 +6,7 @@
|
||||
<meta name="theme-color" content="#0d1117">
|
||||
<title>Oil · MT5</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="style.css?v=136">
|
||||
<link rel="stylesheet" href="style.css?v=137">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Modul-Menü (ganz oben) -->
|
||||
@@ -239,10 +239,17 @@
|
||||
(margin_buffer_pct % der freien Margin). ⚠ BEWUSST hier und nicht in der
|
||||
Trade-Leiste: die ist nur bei OFFENER Position sichtbar, der Einsatz muss
|
||||
aber VOR dem Öffnen einstellbar sein. Wirkt auf ALLE neuen Positionen. -->
|
||||
<span class="mg-field" title="Feste Einsatz-Margin in € — leer/0 = automatisch (95 % der freien Margin). Gilt auch für autonome Trades.">
|
||||
<label for="margin-input">Einsatz</label>
|
||||
<span class="mg-field" title="Feste Einsatz-Margin in € — leer/0 = automatisch (dann gilt der Prozentsatz rechts). Gilt auch für autonome Trades.">
|
||||
<label for="margin-input">Einsatz €</label>
|
||||
<input id="margin-input" type="number" inputmode="decimal" step="10" min="0" placeholder="auto">
|
||||
</span>
|
||||
<!-- Prozent-Gegenstück (User 2026-08-05). Steuert `margin_buffer_pct`, das
|
||||
bisher nur in der ini stand. ⚠ Der feste €-Betrag hat VORRANG — steht er,
|
||||
wird dieses Feld ausgegraut, damit nicht unklar bleibt, was gilt. -->
|
||||
<span class="mg-field" id="marginpct-wrap" title="Einsatz als Prozent der freien Margin (1–99). Greift, solange links kein fester Betrag steht.">
|
||||
<label for="marginpct-input">Einsatz %</label>
|
||||
<input id="marginpct-input" type="number" inputmode="decimal" step="5" min="1" max="99" placeholder="95">
|
||||
</span>
|
||||
<button class="btn long" data-side="long">▲ LONG</button>
|
||||
<button class="btn short" data-side="short">▼ SHORT</button>
|
||||
<button class="btn close" data-side="close">✕ CLOSE</button>
|
||||
@@ -267,6 +274,6 @@
|
||||
<div id="toast" class="toast hidden"></div>
|
||||
|
||||
<script src="lightweight-charts.standalone.production.js?v=114"></script>
|
||||
<script src="app.js?v=136"></script>
|
||||
<script src="app.js?v=137"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -528,3 +528,7 @@ main{padding-bottom:74px} /* Platz für die fixe Leiste */
|
||||
/* aktiv gesetzt = sichtbar hervorgehoben, damit ein fester Einsatz nicht
|
||||
unbemerkt bestehen bleibt */
|
||||
.mg-field input.on { border-color: #d29922; color: #d29922; }
|
||||
/* Prozent-Feld ohne Wirkung, weil links ein FESTER Betrag steht — sichtbar
|
||||
zurückgenommen, statt zwei scheinbar gleichrangige Felder zu zeigen. */
|
||||
.mg-field.muted { opacity: .45; }
|
||||
.mg-field.muted input { border-style: dashed; }
|
||||
|
||||
Reference in New Issue
Block a user