FoxBot Pro analyse les marchés OKX en continu, repère les opportunités
et vous alerte sur Telegram. Vous validez, vous exécutez : manuellement
ou en semi-auto. Le bot suggère, vous décidez.
Démarrer · Gratuit pendant la betaVoir les performances
· Vos clés, votre exchange
{/* scroll cue */}
SCROLL
);
};
/* ---------- Animated dashboard preview ---------- */
const DashboardPreview = () => {
const [pnl, setPnl] = useState(8.19);
useEffect(() => {
const id = setInterval(() => setPnl(p => +(p + (Math.random() - 0.45) * 0.04).toFixed(2)), 1400);
return () => clearInterval(id);
}, []);
// Generate the equity-curve path
const path = useMemo(() => {
const w = 1100, h = 200;
const pts = [];
let y = h * 0.85;
for (let i = 0; i <= 60; i++) {
const x = (i / 60) * w;
y -= 0.6 + Math.sin(i / 4) * 0.8 + Math.random() * 0.4;
pts.push(`${x.toFixed(1)},${Math.max(20, y).toFixed(1)}`);
}
return 'M' + pts.join(' L');
}, []);
return (
);
};
/* ---------- FAQ ---------- */
const FAQ = () => {
const items = [
{
q: 'FoxBot Pro peut-il vider mon compte OKX ?',
a: 'Non. Au moment de connecter votre exchange, vous créez une clé API avec uniquement les permissions Read et Trade, jamais Withdraw. FoxBot Pro ne peut techniquement pas retirer un seul satoshi. Vous gardez vos fonds, sur votre compte, sous votre seule signature.',
},
{
q: 'Quelles sont les performances réelles, pas marketées ?',
a: 'FoxBot Pro est en beta : les chiffres de performance ne sont pas affichés tant que les backtests complets sur données OKX ne sont pas publiés. En attendant, le mode simulation vous laisse valider chaque stratégie sur du papier avant un seul euro de capital réel.',
},
{
q: 'Comment mes clés API sont-elles stockées ?',
a: 'Chiffrement AES-256-GCM au repos, dérivation par utilisateur, transmission TLS 1.3 uniquement. Les clés sont déchiffrées en RAM le temps d\'un appel API, jamais loggées. Architecture inspirée des outils de gestion de secrets type Vault.',
},
{
q: 'Que se passe-t-il si OKX est down ou si ma latence explose ?',
a: 'Health checks toutes les 60 secondes : si la latence dépasse 200ms ou si une stratégie ne valide plus, le bot s\'arrête seul et vous prévient sur Telegram. Les positions ouvertes restent protégées par leur stop-loss exchange, pas un stop logiciel.',
},
{
q: 'Et si je veux annuler ?',
a: 'Pas d\'engagement pendant la beta : vous pouvez arrêter quand vous voulez. Vos positions ouvertes restent telles quelles sur OKX, vous reprenez la main directement. Données conservées 30 jours puis purgées (RGPD).',
},
];
const [open, setOpen] = useState(0);
return (
{items.map((it, i) => (
{open === i && (
{it.a}
)}
))}
);
};
/* ---------- Final CTA ---------- */
/* ---------- DitheringShader: Bayer 4×4 warp halftone (ports paper-design's effect) ---------- */
const DitheringShader = ({ speed = 0.2, color = [0.608, 0.365, 0.940] }) => {
const canvasRef = useRef(null);
const colorRef = useRef(color);
const speedRef = useRef(speed);
useEffect(() => { colorRef.current = color; }, [color]);
useEffect(() => { speedRef.current = speed; }, [speed]);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const gl = canvas.getContext('webgl', { alpha: true, premultipliedAlpha: false });
if (!gl) return;
const vert = `attribute vec2 aPosition; void main(){ gl_Position = vec4(aPosition,0.0,1.0); }`;
const frag = `
precision highp float;
uniform float iTime;
uniform vec2 iResolution;
uniform vec3 uColor;
uniform float uSpeed;
// Bayer 4x4 ordered-dither threshold (returns 0..15 / 16)
float bayer4(vec2 p) {
vec2 q = floor(mod(p, 4.0));
int x = int(q.x);
int y = int(q.y);
float v = 0.0;
if (x == 0 && y == 0) v = 0.0;
else if (x == 1 && y == 0) v = 8.0;
else if (x == 2 && y == 0) v = 2.0;
else if (x == 3 && y == 0) v = 10.0;
else if (x == 0 && y == 1) v = 12.0;
else if (x == 1 && y == 1) v = 4.0;
else if (x == 2 && y == 1) v = 14.0;
else if (x == 3 && y == 1) v = 6.0;
else if (x == 0 && y == 2) v = 3.0;
else if (x == 1 && y == 2) v = 11.0;
else if (x == 2 && y == 2) v = 1.0;
else if (x == 3 && y == 2) v = 9.0;
else if (x == 0 && y == 3) v = 15.0;
else if (x == 1 && y == 3) v = 7.0;
else if (x == 2 && y == 3) v = 13.0;
else if (x == 3 && y == 3) v = 5.0;
return v / 16.0;
}
void main() {
// pixelate into 4×4 cells
vec2 cellSize = vec2(4.0);
vec2 cell = floor(gl_FragCoord.xy / cellSize);
vec2 uv = cell * cellSize / iResolution.xy;
// warp value field (animated)
float t = iTime * uSpeed;
vec2 p = uv * 3.2;
float v1 = sin(p.x + sin(p.y * 1.3 + t));
float v2 = cos(p.y + cos(p.x * 0.9 + t * 1.1));
float wave = (v1 + v2) * 0.5;
// radial pulse so the centre breathes
float r = length(uv - vec2(0.5, 0.55));
wave += sin(r * 8.0 - t * 1.3) * 0.45;
wave -= r * 1.2; // fade toward edges
float value = clamp(0.5 + 0.5 * wave, 0.0, 1.0);
// ordered dither
float on = step(bayer4(cell), value);
gl_FragColor = vec4(uColor * on, on * 0.9);
}
`;
const compile = (type, src) => {
const sh = gl.createShader(type);
gl.shaderSource(sh, src);
gl.compileShader(sh);
if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(sh));
}
return sh;
};
const program = gl.createProgram();
gl.attachShader(program, compile(gl.VERTEX_SHADER, vert));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, frag));
gl.linkProgram(program);
gl.useProgram(program);
const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, -1,1, 1,-1, 1,1]), gl.STATIC_DRAW);
const aPos = gl.getAttribLocation(program, 'aPosition');
gl.enableVertexAttribArray(aPos);
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
const uTime = gl.getUniformLocation(program, 'iTime');
const uRes = gl.getUniformLocation(program, 'iResolution');
const uColor = gl.getUniformLocation(program, 'uColor');
const uSpeed = gl.getUniformLocation(program, 'uSpeed');
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
const resize = () => {
const dpr = Math.min(window.devicePixelRatio || 1, 2);
const r = canvas.getBoundingClientRect();
canvas.width = Math.max(1, Math.floor(r.width * dpr));
canvas.height = Math.max(1, Math.floor(r.height * dpr));
gl.viewport(0, 0, canvas.width, canvas.height);
};
resize();
const ro = new ResizeObserver(resize);
ro.observe(canvas);
let rafId;
const render = (t) => {
gl.uniform1f(uTime, t * 0.001);
gl.uniform2f(uRes, canvas.width, canvas.height);
gl.uniform3fv(uColor, colorRef.current);
gl.uniform1f(uSpeed, speedRef.current);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
rafId = requestAnimationFrame(render);
};
rafId = requestAnimationFrame(render);
return () => {
cancelAnimationFrame(rafId);
ro.disconnect();
};
}, []);
return (
);
};
/* ---------- Final CTA (dithering hero card) ---------- */
const FinalCTA = () => {
const [hovered, setHovered] = useState(false);
return (
);
};
/* useCursorSpotlight: tracks mouse inside ref'd element, exposes --mx / --my CSS vars */
const useCursorSpotlight = () => {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const onMove = (e) => {
const r = el.getBoundingClientRect();
el.style.setProperty('--mx', `${e.clientX - r.left}px`);
el.style.setProperty('--my', `${e.clientY - r.top}px`);
el.style.setProperty('--spot', '1');
};
const onLeave = () => el.style.setProperty('--spot', '0');
el.addEventListener('mousemove', onMove);
el.addEventListener('mouseleave', onLeave);
return () => {
el.removeEventListener('mousemove', onMove);
el.removeEventListener('mouseleave', onLeave);
};
}, []);
return ref;
};
/* ---------- Root ---------- */
const App = () => (
<>
Des signaux haute conviction, scannés en temps réel.>}
description={<>
Le moteur FoxBot Pro analyse en continu une dizaine de paires sur OKX (50+ à venir) et ne
remonte que les setups validés sur 6 indicateurs techniques. Chaque
signal arrive avec son entry, ses TP, son SL, son ratio R/R et un
score de conviction sur 10.
Vous restez en contrôle : paper trade pour valider, ou réel quand
vous êtes prêt.
>}
mockup={}
/>
Un dashboard qui dit la vérité, pas du marketing.>}
description={<>
P&L, win rate, drawdown, courbe d'equity, positions ouvertes, top
signaux du jour, tout sur un seul écran, sans filtres, sans
chiffres gonflés.
Connecté à votre compte OKX réel ou en mode paper trading. Vous voyez exactement ce que voit le bot.
>}
mockup={}
/>
>
);
ReactDOM.createRoot(document.getElementById('app')).render();