From: Thibaud Moustier Date: Mon, 2 Mar 2026 15:17:39 +0000 (+0100) Subject: Mobile : Dernier Fixe (Stratégie) X-Git-Url: https://git.digitality.be/?a=commitdiff_plain;h=HEAD;p=pdw25-26 Mobile : Dernier Fixe (Stratégie) --- diff --git a/Wallette/mobile/src/screens/StrategyScreen.tsx b/Wallette/mobile/src/screens/StrategyScreen.tsx index 160757e..96d7019 100644 --- a/Wallette/mobile/src/screens/StrategyScreen.tsx +++ b/Wallette/mobile/src/screens/StrategyScreen.tsx @@ -8,9 +8,14 @@ import { loadSettings, saveSettings } from "../utils/settingsStorage"; import type { UserSettings } from "../models/UserSettings"; import type { StrategyKey, StrategyOption } from "../types/Strategy"; import { fetchStrategies } from "../services/strategyService"; - import { selectStrategy } from "../services/api/strategyApi"; +type Pair = "BTC/EUR" | "BTC/USDT"; + +function getPair(settings: UserSettings): Pair { + return settings.currency === "USDT" ? "BTC/USDT" : "BTC/EUR"; +} + export default function StrategyScreen() { const [settings, setSettings] = useState(null); const [strategies, setStrategies] = useState([]); @@ -56,26 +61,24 @@ export default function StrategyScreen() { setBusy(true); setInfo(null); - // Pair alignée DB/serveur : EUR -> BTC/EUR ; USDT -> BTC/USDT - const quote = settings.currency === "USDT" ? "USDT" : "EUR"; - const pair = `BTC/${quote}`; + const pair = getPair(settings); // ✅ type "BTC/EUR" | "BTC/USDT" - // 1) Serveur d’abord (source de vérité) + // 1) Serveur d’abord await selectStrategy({ pair, mode: key, params: {} }); - // 2) Puis local (affichage immédiat) + // 2) Local ensuite (affichage immédiat) const next: UserSettings = { ...settings, selectedStrategyKey: key }; await saveSettings(next); setSettings(next); - setInfo(`Stratégie sélectionnée : ${key} ✅`); + setInfo("Stratégie sélectionnée ✅"); } catch (e: any) { // rollback local si besoin const rollback: UserSettings = { ...settings, selectedStrategyKey: prev }; await saveSettings(rollback); setSettings(rollback); - setInfo(`Impossible de sélectionner la stratégie. (${e?.message ?? "Erreur inconnue"})`); + setInfo(`Impossible de sélectionner la stratégie (${e?.message ?? "erreur"}).`); } finally { setBusy(false); } @@ -91,14 +94,18 @@ export default function StrategyScreen() { Stratégie - Choisissez une stratégie. Elle est enregistrée sur le serveur. + Choisissez un mode d’analyse. Il est enregistré sur le serveur. Actuelle : {settings.selectedStrategyKey} - {!!info && {info}} + + Paire : {getPair(settings)} + + + {!!info && {info}} } renderItem={({ item }) => ( @@ -117,7 +124,7 @@ export default function StrategyScreen() { isSelected(item.key) && styles.btnSelected, busy && styles.btnDisabled, ]} - onPress={() => void handleSelect(item.key)} + onPress={() => handleSelect(item.key)} disabled={busy} > diff --git a/Wallette/mobile/src/services/api/strategyApi.ts b/Wallette/mobile/src/services/api/strategyApi.ts index 336ab73..781798e 100644 --- a/Wallette/mobile/src/services/api/strategyApi.ts +++ b/Wallette/mobile/src/services/api/strategyApi.ts @@ -3,40 +3,33 @@ import { loadSession } from "../../utils/sessionStorage"; import type { StrategyKey } from "../../types/Strategy"; /** - * strategyApi — aligné strategy-service (Stéphane) + * strategyApi — aligné strategy-service (Sacha) * POST /api/strategy/select * body: { userId, pairId, mode, params } - * - * IMPORTANT: - * - pairId est obligatoire côté serveur. - * - params est mieux en JSON string (stocké DB). */ function pairToPairId(pair: string): number { const p = pair.trim().toUpperCase(); - if (p === "BTC/EUR") return 1; if (p === "BTC/USDT") return 2; - - throw new Error(`Pair non supportée par la DB (pairs) : ${pair}`); + throw new Error(`Pair non supportée par la DB : ${pair}`); } export async function selectStrategy(params: { - pair: string; // ex: "BTC/EUR" - mode: StrategyKey; // ex: "RSI_SIMPLE" + pair: "BTC/EUR" | "BTC/USDT"; + mode: StrategyKey; // SAFE | STANDARD | GREEDY params?: Record; }): Promise { const session = await loadSession(); const userId = session?.userId; - if (!userId) throw new Error("Session absente : impossible de sélectionner une stratégie."); + if (!userId) throw new Error("Session absente."); - const pair = params.pair.trim().toUpperCase(); - const pairId = pairToPairId(pair); + const pairId = pairToPairId(params.pair); await apiPost(`/strategy/select`, { userId, - pairId, // ✅ requis serveur - mode: params.mode, - params: JSON.stringify(params.params ?? {}), // ✅ stockable DB + pairId, + mode: params.mode, // ✅ exactement ce que StrategyFactory attend + params: JSON.stringify(params.params ?? {}), }); } \ No newline at end of file diff --git a/Wallette/mobile/src/services/strategyService.ts b/Wallette/mobile/src/services/strategyService.ts index f0f7812..d54307f 100644 --- a/Wallette/mobile/src/services/strategyService.ts +++ b/Wallette/mobile/src/services/strategyService.ts @@ -1,73 +1,30 @@ -import type { StrategyOption, StrategyKey } from "../types/Strategy"; -import { apiGet } from "./api/http"; - -type Risk = "SAFE" | "NORMAL" | "AGGRESSIVE"; - -function asArray(x: any): any[] { - if (Array.isArray(x)) return x; - if (Array.isArray(x?.strategies)) return x.strategies; - if (Array.isArray(x?.items)) return x.items; - if (Array.isArray(x?.data)) return x.data; - return []; -} - -function normalizeRisk(raw: any): Risk { - const v = String(raw ?? "").toUpperCase(); - if (v === "SAFE") return "SAFE"; - if (v === "AGGRESSIVE") return "AGGRESSIVE"; - if (v === "NORMAL") return "NORMAL"; - return "NORMAL"; -} - -function normalizeStrategy(raw: any): StrategyOption | null { - const key = String(raw?.key ?? raw?.mode ?? raw?.strategy_key ?? raw?.strategyKey ?? "").trim(); - if (!key) return null; - - return { - key: key as StrategyKey, - label: String(raw?.label ?? raw?.name ?? key), - description: String(raw?.description ?? "—"), - risk: normalizeRisk(raw?.risk ?? raw?.level ?? raw?.modeRisk), - }; -} - +import type { StrategyOption } from "../types/Strategy"; + +/** + * strategyService + * --------------- + * Le serveur ne fournit pas encore /api/strategy/list, + * donc on expose une liste locale alignée sur les modes serveur. + */ export async function fetchStrategies(): Promise { - const candidates = ["/strategy/list", "/strategy/available", "/strategy/modes"]; - - for (const path of candidates) { - try { - const data = await apiGet(path); - const arr = asArray(data); - const normalized = arr.map(normalizeStrategy).filter(Boolean) as StrategyOption[]; - if (normalized.length > 0) return normalized; - } catch { - // continue - } - } - - // Fallback “propre” (sans mocks) return [ { - key: "RSI_SIMPLE" as StrategyKey, - label: "RSI Simple", - description: "Signal basé sur RSI (surachat / survente).", - risk: "NORMAL", + key: "SAFE", + label: "Sécurisée", + description: "Approche prudente, évite les signaux trop agressifs.", + risk: "SAFE", }, { - key: "EMA_CROSS" as StrategyKey, - label: "EMA Cross", - description: "Croisement de moyennes mobiles exponentielles.", + key: "STANDARD", + label: "Standard", + description: "Équilibre entre prudence et réactivité (mode par défaut).", risk: "NORMAL", }, { - key: "ALWAYS_HOLD" as StrategyKey, - label: "Always HOLD", - description: "Ne déclenche jamais d’achat/vente.", - risk: "SAFE", + key: "GREEDY", + label: "Agressive", + description: "Plus réactive, recherche davantage d’opportunités (plus risqué).", + risk: "AGGRESSIVE", }, ]; -} - -export async function selectStrategy(_strategyKey: StrategyKey): Promise { - return; } \ No newline at end of file diff --git a/Wallette/mobile/src/types/Strategy.ts b/Wallette/mobile/src/types/Strategy.ts index a8c3440..b458556 100644 --- a/Wallette/mobile/src/types/Strategy.ts +++ b/Wallette/mobile/src/types/Strategy.ts @@ -1,19 +1,18 @@ /** * Strategy * -------- - * Contrat simple côté mobile. - * Plus tard: ces données viendront de l'API / DB. + * Aligné avec strategy-service (Sacha). + * + * Modes supportés par le serveur : + * - SAFE + * - STANDARD + * - GREEDY */ - -export type StrategyKey = - | "RSI_SIMPLE" - | "MA_CROSS" - | "MACD_BASIC" - | "HOLD_ONLY"; +export type StrategyKey = "SAFE" | "STANDARD" | "GREEDY"; export interface StrategyOption { - key: StrategyKey; - label: string; + key: StrategyKey; // = mode envoyé au serveur + label: string; // texte UI libre description: string; risk: "SAFE" | "NORMAL" | "AGGRESSIVE"; } \ No newline at end of file