]> git.digitality.be Git - pdw25-26/commitdiff
Mobile : Dernier Fixe (Stratégie) main
authorThibaud Moustier <thibaudmoustier0@gmail.com>
Mon, 2 Mar 2026 15:17:39 +0000 (16:17 +0100)
committerThibaud Moustier <thibaudmoustier0@gmail.com>
Mon, 2 Mar 2026 15:17:39 +0000 (16:17 +0100)
Wallette/mobile/src/screens/StrategyScreen.tsx
Wallette/mobile/src/services/api/strategyApi.ts
Wallette/mobile/src/services/strategyService.ts
Wallette/mobile/src/types/Strategy.ts

index 160757e2b3fee518df08d9302c5239e74c716ad8..96d70195cba1fd645b8e5740b12329e93e2c8db6 100644 (file)
@@ -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 type { UserSettings } from "../models/UserSettings";
 import type { StrategyKey, StrategyOption } from "../types/Strategy";
 import { fetchStrategies } from "../services/strategyService";
-
 import { selectStrategy } from "../services/api/strategyApi";
 
 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<UserSettings | null>(null);
   const [strategies, setStrategies] = useState<StrategyOption[]>([]);
 export default function StrategyScreen() {
   const [settings, setSettings] = useState<UserSettings | null>(null);
   const [strategies, setStrategies] = useState<StrategyOption[]>([]);
@@ -56,26 +61,24 @@ export default function StrategyScreen() {
       setBusy(true);
       setInfo(null);
 
       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: {} });
 
       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);
 
       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);
 
     } 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);
     }
     } finally {
       setBusy(false);
     }
@@ -91,14 +94,18 @@ export default function StrategyScreen() {
           <View style={ui.card}>
             <Text style={ui.title}>Stratégie</Text>
             <Text style={ui.muted}>
           <View style={ui.card}>
             <Text style={ui.title}>Stratégie</Text>
             <Text style={ui.muted}>
-              Choisissez une stratégie. Elle est enregistrée sur le serveur.
+              Choisissez un mode d’analyse. Il est enregistré sur le serveur.
             </Text>
 
             <Text style={[ui.muted, { marginTop: 8 }]}>
               Actuelle : <Text style={styles.boldInline}>{settings.selectedStrategyKey}</Text>
             </Text>
 
             </Text>
 
             <Text style={[ui.muted, { marginTop: 8 }]}>
               Actuelle : <Text style={styles.boldInline}>{settings.selectedStrategyKey}</Text>
             </Text>
 
-            {!!info && <Text style={[ui.muted, { marginTop: 8 }]}>{info}</Text>}
+            <Text style={[ui.muted, { marginTop: 6 }]}>
+              Paire : <Text style={styles.boldInline}>{getPair(settings)}</Text>
+            </Text>
+
+            {!!info && <Text style={[ui.muted, { marginTop: 10 }]}>{info}</Text>}
           </View>
         }
         renderItem={({ item }) => (
           </View>
         }
         renderItem={({ item }) => (
@@ -117,7 +124,7 @@ export default function StrategyScreen() {
                 isSelected(item.key) && styles.btnSelected,
                 busy && styles.btnDisabled,
               ]}
                 isSelected(item.key) && styles.btnSelected,
                 busy && styles.btnDisabled,
               ]}
-              onPress={() => void handleSelect(item.key)}
+              onPress={() => handleSelect(item.key)}
               disabled={busy}
             >
               <Text style={ui.buttonText}>
               disabled={busy}
             >
               <Text style={ui.buttonText}>
index 336ab73d26d3bb3da4a45559ca6444e31f4593ec..781798ef53fa5e704c162608a66cb4b4d7fd54c8 100644 (file)
@@ -3,40 +3,33 @@ import { loadSession } from "../../utils/sessionStorage";
 import type { StrategyKey } from "../../types/Strategy";
 
 /**
 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 }
  * 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();
  */
 
 function pairToPairId(pair: string): number {
   const p = pair.trim().toUpperCase();
-
   if (p === "BTC/EUR") return 1;
   if (p === "BTC/USDT") return 2;
   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: {
 }
 
 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<string, unknown>;
 }): Promise<void> {
   const session = await loadSession();
   const userId = session?.userId;
   params?: Record<string, unknown>;
 }): Promise<void> {
   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,
 
   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
   });
 }
\ No newline at end of file
index f0f7812ad8e4e57962c2b1675a38857f383810bf..d54307f42114ece000629f6ec990bcb6e97615f5 100644 (file)
@@ -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<StrategyOption[]> {
 export async function fetchStrategies(): Promise<StrategyOption[]> {
-  const candidates = ["/strategy/list", "/strategy/available", "/strategy/modes"];
-
-  for (const path of candidates) {
-    try {
-      const data = await apiGet<any>(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 [
     {
   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",
     },
     {
       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<void> {
-  return;
 }
\ No newline at end of file
 }
\ No newline at end of file
index a8c3440163e90b14f245fe3af3a147f975cde489..b458556198580d7c10c6a559a1df5e1f169a73c8 100644 (file)
@@ -1,19 +1,18 @@
 /**
  * Strategy
  * --------
 /**
  * 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 {
 
 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
   description: string;
   risk: "SAFE" | "NORMAL" | "AGGRESSIVE";
 }
\ No newline at end of file