Files
wevia-brain/s89-arsenal-screens/arbitrage-bot.html
2026-04-12 23:01:36 +02:00

68 lines
7.7 KiB
HTML
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>Conversion Arbitrage | Arsenal</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<style>*{margin:0;padding:0;box-sizing:border-box}:root{--bg:#060a14;--s:#0c1220;--c:#111827;--b:#1e293b;--cy:#22d3ee;--gn:#10b981;--rd:#ef4444;--or:#f59e0b;--pu:#a855f7;--yl:#eab308;--t:#e2e8f0;--d:#64748b}body{font-family:'DM Sans',sans-serif;background:var(--bg);color:var(--t);min-height:100vh;padding:20px}
.hdr{display:flex;align-items:center;gap:15px;margin-bottom:24px;padding-bottom:16px;border-bottom:1px solid var(--b)}.hdr h1{font-size:22px}.hdr h1 span{color:var(--yl)}.badge{padding:3px 10px;border-radius:20px;font-size:11px;font-weight:600;background:rgba(234,179,8,.15);color:var(--yl)}
.stats{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:20px}.st{background:var(--s);border:1px solid var(--b);border-radius:12px;padding:14px;text-align:center}.sv{font-family:'JetBrains Mono',monospace;font-size:22px;font-weight:700;color:var(--yl)}.sl{font-size:10px;color:var(--d);text-transform:uppercase;margin-top:4px}
.grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:20px}.card{background:var(--s);border:1px solid var(--b);border-radius:14px;padding:20px}.card h3{font-size:14px;color:var(--yl);margin-bottom:12px;text-transform:uppercase;letter-spacing:1px}
.btn{padding:8px 16px;border:none;border-radius:8px;font-weight:600;cursor:pointer;font-size:12px}.btn-p{background:linear-gradient(135deg,var(--yl),#ca8a04);color:#000}.btn-s{background:var(--c);color:var(--t);border:1px solid var(--b)}
.offer-row{display:flex;align-items:center;gap:12px;padding:12px;background:var(--c);border-radius:10px;margin-bottom:8px}.offer-epc{font-family:'JetBrains Mono';font-size:20px;font-weight:700;color:var(--yl);min-width:80px}.offer-info{flex:1}.offer-name{font-weight:600;font-size:13px}.offer-meta{font-size:11px;color:var(--d)}.offer-payout{font-family:'JetBrains Mono';font-size:14px;font-weight:600;color:var(--gn)}
input,select{background:var(--c);border:1px solid var(--b);border-radius:8px;padding:8px;color:var(--t);font-size:12px;margin-bottom:6px;width:100%}
.reco{background:linear-gradient(135deg,rgba(234,179,8,.1),var(--c));border:2px solid var(--yl);border-radius:14px;padding:20px;text-align:center;margin-bottom:16px}.reco-offer{font-size:20px;font-weight:700;margin:8px 0}.reco-epc{font-family:'JetBrains Mono';font-size:36px;font-weight:700;color:var(--yl)}.reco-reason{font-size:12px;color:var(--d);margin-top:8px}
.decision-row{padding:10px;border-bottom:1px solid var(--b);font-size:12px}.decision-gain{color:var(--gn);font-family:'JetBrains Mono';font-weight:700}
</style></head><body>
<div class="hdr"><div style="font-size:32px">💰</div><h1>Conversion <span>Arbitrage</span> Bot</h1><span class="badge">● LIVE</span><div style="margin-left:auto;font-family:'JetBrains Mono';font-size:12px;color:var(--d)" id="clock"></div><div style="margin-left:16px"><a href="command-center.html" class="btn btn-s">← Command Center</a></div></div>
<div class="stats"><div class="st"><div class="sv" id="sOffers">0</div><div class="sl">Active Offers</div></div><div class="st"><div class="sv" id="sNetworks">0</div><div class="sl">Networks</div></div><div class="st"><div class="sv" id="sBestEpc">-</div><div class="sl">Best EPC</div></div><div class="st"><div class="sv" id="sAvgEpc">-</div><div class="sl">Avg EPC</div></div><div class="st"><div class="sv" id="sPivots">0</div><div class="sl">Auto-Pivots</div></div></div>
<div class="reco" id="recoBox"><div style="font-size:12px;color:var(--d)">🎯 RECOMMENDED NOW</div><div class="reco-offer" id="recoName">Loading...</div><div class="reco-epc" id="recoEpc"></div><div class="reco-reason" id="recoReason"></div></div>
<div class="grid">
<div class="card"><h3>📊 Offers by EPC</h3><div id="offerList" style="max-height:400px;overflow-y:auto"></div></div>
<div class="card"><h3>🔄 Pivot Decisions</h3><div id="decisionList" style="max-height:200px;overflow-y:auto"></div>
<h3 style="margin-top:16px"> Add Offer</h3>
<select id="aNetwork"><option value="CX3 Ads">CX3 Ads</option><option value="Double M">Double M</option><option value="Other">Other</option></select>
<input id="aName" placeholder="Offer name"><input id="aCategory" placeholder="Category (insurance, finance, gambling...)">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:6px"><input id="aEpc" placeholder="EPC"><input id="aPayout" placeholder="Payout €"></div>
<select id="aCountry"><option value="FR">France</option><option value="DE">Germany</option><option value="GB">UK</option><option value="NL">Netherlands</option></select>
<button class="btn btn-p" onclick="addOffer()" style="width:100%">Add Offer</button></div>
</div>
<script>
const API='/api/arbitrage-bot.php';
function updateClock(){document.getElementById('clock').textContent=new Date().toLocaleTimeString('fr-FR');}setInterval(updateClock,1000);updateClock();
async function init(){await Promise.all([loadStats(),loadOffers(),loadReco(),loadDecisions()]);}
async function loadStats(){
const r=await fetch(API+'?action=stats');const d=await r.json();const o=d.offers||{};
document.getElementById('sOffers').textContent=o.total||0;
document.getElementById('sNetworks').textContent=o.networks||0;
document.getElementById('sBestEpc').textContent='€'+(o.best_epc||0);
document.getElementById('sAvgEpc').textContent='€'+(o.avg_epc||0);
document.getElementById('sPivots').textContent=d.decisions?.total_pivots||0;
}
async function loadOffers(){
const r=await fetch(API+'?action=offers');const d=await r.json();
const el=document.getElementById('offerList');el.innerHTML='';
(d.offers||[]).forEach(o=>{
el.innerHTML+=`<div class="offer-row"><div class="offer-epc">€${parseFloat(o.epc).toFixed(2)}</div><div class="offer-info"><div class="offer-name">${o.offer_name}</div><div class="offer-meta">${o.network} · ${o.category} · ${o.country}</div></div><div class="offer-payout">€${parseFloat(o.payout).toFixed(0)}</div></div>`;
});
}
async function loadReco(){
const r=await fetch(API+'?action=recommend&segment=FR');const d=await r.json();
if(d.recommended){
document.getElementById('recoName').textContent=d.recommended.offer_name;
document.getElementById('recoEpc').textContent='€'+parseFloat(d.recommended.adjusted_epc).toFixed(2);
document.getElementById('recoReason').textContent=d.reason;
}
}
async function loadDecisions(){
const r=await fetch(API+'?action=decisions');const d=await r.json();
const el=document.getElementById('decisionList');el.innerHTML='';
(d.decisions||[]).forEach(dec=>{
el.innerHTML+=`<div class="decision-row">🔄 <strong>${dec.offer_name||'?'}</strong> — ${dec.segment}<br><span class="decision-gain">+€${parseFloat(dec.epc_diff||0).toFixed(4)}</span> <span style="color:var(--d)">${dec.decided_at?.substr(0,16)}</span></div>`;
});
if(!d.decisions?.length) el.innerHTML='<div style="text-align:center;padding:20px;color:var(--d)">No pivot decisions yet</div>';
}
async function addOffer(){
const data={action:'add_offer',network:document.getElementById('aNetwork').value,offer_name:document.getElementById('aName').value,category:document.getElementById('aCategory').value,epc:parseFloat(document.getElementById('aEpc').value)||0,payout:parseFloat(document.getElementById('aPayout').value)||0,country:document.getElementById('aCountry').value};
await fetch(API,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)});
init();
}
init();setInterval(()=>{loadReco();loadStats();},30000);
</script></body></html>