68 lines
7.7 KiB
HTML
Executable File
68 lines
7.7 KiB
HTML
Executable File
<!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>
|