|
|
@@ -1,11 +1,13 @@
|
|
|
<script>
|
|
|
import Header from '$lib/layout/Header.svelte';
|
|
|
- import Tables from '$lib/components/Tables.svelte';
|
|
|
- import BuyPanel from '$lib/components/trading/BuyPanel.svelte';
|
|
|
- import SellPanel from '$lib/components/trading/SellPanel.svelte';
|
|
|
+ import TabelaOrdens from '$lib/components/trading/TabelaOrdens.svelte';
|
|
|
+ import GraficoCandlestick from '$lib/components/trading/GraficoCandlestick.svelte';
|
|
|
+ import BoletaCompra from '$lib/components/trading/BoletaCompra.svelte';
|
|
|
+ import BoletaVenda from '$lib/components/trading/BoletaVenda.svelte';
|
|
|
import { writable } from 'svelte/store';
|
|
|
import { onMount } from 'svelte';
|
|
|
import { browser } from '$app/environment';
|
|
|
+ import { ordensCompra as ordensCompraMock, ordensVenda as ordensVendaMock, startOrdensSimulator } from '$lib/mock/ordens.js';
|
|
|
|
|
|
const breadcrumb = [{ label: 'Início' }, { label: 'Trading', active: true }];
|
|
|
|
|
|
@@ -22,6 +24,27 @@
|
|
|
if (saved) orders.set(JSON.parse(saved));
|
|
|
} catch {}
|
|
|
}
|
|
|
+
|
|
|
+ const stopSimCompra = startOrdensSimulator({
|
|
|
+ get: () => ordensCompra,
|
|
|
+ set: (next) => { ordensCompra = next; },
|
|
|
+ intervalMs: 1500,
|
|
|
+ maxItems: 60,
|
|
|
+ minItems: 8
|
|
|
+ });
|
|
|
+
|
|
|
+ const stopSimVenda = startOrdensSimulator({
|
|
|
+ get: () => ordensVenda,
|
|
|
+ set: (next) => { ordensVenda = next; },
|
|
|
+ intervalMs: 1500,
|
|
|
+ maxItems: 60,
|
|
|
+ minItems: 8
|
|
|
+ });
|
|
|
+
|
|
|
+ return () => {
|
|
|
+ stopSimCompra?.();
|
|
|
+ stopSimVenda?.();
|
|
|
+ };
|
|
|
});
|
|
|
|
|
|
function addOrder(order) {
|
|
|
@@ -84,14 +107,14 @@
|
|
|
{ key: 'status', label: 'Status' }
|
|
|
];
|
|
|
|
|
|
-$: pendingBuys = $orders.filter((o) => o.side === 'Compra' && o.type === 'limit' && o.status === 'Aberta');
|
|
|
-$: pendingSells = $orders.filter((o) => o.side === 'Venda' && o.type === 'limit' && o.status === 'Aberta');
|
|
|
+$: pendingBuys = $orders.filter((o) => o.side === 'Compra' && o.status === 'Aberta');
|
|
|
+$: pendingSells = $orders.filter((o) => o.side === 'Venda' && o.status === 'Aberta');
|
|
|
|
|
|
$: displayPendingBuys = pendingBuys.map((o) => ({
|
|
|
side: o.side,
|
|
|
- price: formatEasyToken(o.price),
|
|
|
+ price: formatBRL(o.price),
|
|
|
amount: formatEasyToken(o.amount),
|
|
|
- total: formatEasyToken(o.total),
|
|
|
+ total: formatBRL(o.total),
|
|
|
status: o.status
|
|
|
}));
|
|
|
|
|
|
@@ -102,26 +125,106 @@ $: displayPendingSells = pendingSells.map((o) => ({
|
|
|
total: formatBRL(o.total),
|
|
|
status: o.status
|
|
|
}));
|
|
|
+
|
|
|
+ const tokens = [
|
|
|
+ { id: 'TK-SOJA', label: 'Soja (saca 60kg)', price: 125.50 },
|
|
|
+ { id: 'TK-MILHO', label: 'Milho (saca 60kg)', price: 78.90 },
|
|
|
+ { id: 'TK-CAFE', name: 'Café (saca 60kg)' },
|
|
|
+ ];
|
|
|
+
|
|
|
+ const stateOptions = ['SP','PR','RS','MG','MT','GO','MS','BA','SC','RO','PA'];
|
|
|
+ let selectedState = 'SP';
|
|
|
+ let selectedCommodity = tokens?.[0]?.id ?? '';
|
|
|
+
|
|
|
+ let showBuyModal = false;
|
|
|
+ let showSellModal = false;
|
|
|
+
|
|
|
+ $: selectedCommodityObj = tokens.find((t) => t.id === selectedCommodity);
|
|
|
+ $: selectedCommodityLabel = selectedCommodityObj?.label || selectedCommodityObj?.name;
|
|
|
+
|
|
|
+ let ordensCompra = ordensCompraMock.slice();
|
|
|
+ let ordensVenda = ordensVendaMock.slice();
|
|
|
+ $: ultimaVenda = (ordensVenda && ordensVenda.length)
|
|
|
+ ? { valor: Number(ordensVenda[ordensVenda.length - 1]?.valor ?? 0), quantidade: Number(ordensVenda[ordensVenda.length - 1]?.quantidade ?? 0) }
|
|
|
+ : { valor: 0, quantidade: 0 };
|
|
|
+
|
|
|
+ const dadosMock = [
|
|
|
+ { date: '2025-10-01', valor: 9.98, high: 10.05, low: 9.90 },
|
|
|
+ { date: '2025-10-02', valor: 10.12, high: 10.25, low: 9.95 },
|
|
|
+ { date: '2025-10-03', valor: 9.85, high: 9.92, low: 9.60 },
|
|
|
+ { date: '2025-10-04', valor: 10.30, high: 10.55, low: 10.10 },
|
|
|
+ { date: '2025-10-05', valor: 10.05, high: 10.20, low: 9.85 },
|
|
|
+ { date: '2025-10-06', valor: 9.70, high: 9.85, low: 9.45 },
|
|
|
+ { date: '2025-10-07', valor: 10.45, high: 10.75, low: 10.25 },
|
|
|
+ { date: '2025-10-08', valor: 10.60, high: 10.80, low: 10.40 },
|
|
|
+ { date: '2025-10-09', valor: 9.55, high: 9.70, low: 9.20 }, // forte queda
|
|
|
+ { date: '2025-10-10', valor: 9.30, high: 9.50, low: 9.00 }, // fundo do poço
|
|
|
+ { date: '2025-10-11', valor: 9.85, high: 10.00, low: 9.60 }, // leve recuperação
|
|
|
+ { date: '2025-10-12', valor: 10.50, high: 10.80, low: 10.30 }, // disparada
|
|
|
+ { date: '2025-10-13', valor: 10.75, high: 11.10, low: 10.60 },
|
|
|
+ { date: '2025-10-14', valor: 10.95, high: 11.20, low: 10.80 }, // pico máximo
|
|
|
+ { date: '2025-10-15', valor: 10.40, high: 10.60, low: 10.10 },
|
|
|
+ { date: '2025-10-16', valor: 10.10, high: 10.25, low: 9.90 },
|
|
|
+ { date: '2025-10-17', valor: 9.85, high: 9.95, low: 9.60 },
|
|
|
+ { date: '2025-10-18', valor: 9.20, high: 9.35, low: 8.95 }, // nova queda brusca
|
|
|
+ { date: '2025-10-19', valor: 8.85, high: 9.00, low: 8.55 },
|
|
|
+ { date: '2025-10-20', valor: 9.50, high: 9.70, low: 9.20 },
|
|
|
+ { date: '2025-10-21', valor: 9.95, high: 10.10, low: 9.80 },
|
|
|
+ { date: '2025-10-22', valor: 10.25, high: 10.50, low: 10.05 },
|
|
|
+ { date: '2025-10-23', valor: 10.90, high: 11.15, low: 10.75 }, // novo pico
|
|
|
+ { date: '2025-10-24', valor: 11.40, high: 11.75, low: 11.10 },
|
|
|
+ { date: '2025-10-25', valor: 13.75, high: 13.95, low: 13.50 },
|
|
|
+ { date: '2025-10-26', valor: 13.60, high: 13.80, low: 13.40 },
|
|
|
+ { date: '2025-10-27', valor: 9.30, high: 9.45, low: 9.00 }, // queda acentuada
|
|
|
+ { date: '2025-10-28', valor: 9.10, high: 9.25, low: 8.80 },
|
|
|
+ { date: '2025-10-29', valor: 9.60, high: 9.80, low: 9.40 },
|
|
|
+ { date: '2025-10-30', valor: 10.25, high: 10.50, low: 10.05 },
|
|
|
+ { date: '2025-10-31', valor: 10.80, high: 11.00, low: 10.65 }, // novo rally
|
|
|
+ { date: '2025-11-01', valor: 11.20, high: 11.45, low: 11.00 },
|
|
|
+ { date: '2025-11-02', valor: 10.95, high: 11.10, low: 10.70 },
|
|
|
+ { date: '2025-11-03', valor: 10.50, high: 10.65, low: 10.30 },
|
|
|
+ { date: '2025-11-04', valor: 9.80, high: 9.95, low: 9.55 }, // nova correção
|
|
|
+ { date: '2025-11-05', valor: 10.05, high: 10.30, low: 9.85 }
|
|
|
+ ];
|
|
|
</script>
|
|
|
|
|
|
<div>
|
|
|
- <Header title="Trading" subtitle="Trading do sistema" breadcrumb={breadcrumb} />
|
|
|
+ <Header title="Trading" subtitle="Trading do sistema" breadcrumb={breadcrumb}>
|
|
|
+ <svelte:fragment slot="extra">
|
|
|
+ <div class="flex items-center gap-3">
|
|
|
+ <button class="px-3 py-1.5 rounded bg-green-600 hover:bg-green-700 text-white focus:outline-none focus:ring-2 focus:ring-green-500" on:click={() => (showBuyModal = true)}>COMPRAR</button>
|
|
|
+ <button class="px-3 py-1.5 rounded bg-red-600 hover:bg-red-700 text-white focus:outline-none focus:ring-2 focus:ring-red-500" on:click={() => (showSellModal = true)}>VENDER</button>
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <span class="text-xs text-gray-600 dark:text-gray-300">Estado</span>
|
|
|
+ <select bind:value={selectedState} class="block w-32 rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
|
|
+ {#each stateOptions as uf}
|
|
|
+ <option value={uf}>{uf}</option>
|
|
|
+ {/each}
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
+ <span class="text-xs text-gray-600 dark:text-gray-300">Commodity</span>
|
|
|
+ <select bind:value={selectedCommodity} class="block w-56 rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
|
|
+ {#each tokens as t}
|
|
|
+ <option value={t.id}>{t.label || t.name}</option>
|
|
|
+ {/each}
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </svelte:fragment>
|
|
|
+ </Header>
|
|
|
|
|
|
<div class="p-4 space-y-4">
|
|
|
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
- <BuyPanel
|
|
|
- referencePrice={currentPrice}
|
|
|
- on:confirm={(e) => addOrder({ side: 'Compra', price: e.detail.price, amount: e.detail.amount, total: e.detail.total, status: 'Aberta', type: e.detail.type })}
|
|
|
- />
|
|
|
- <SellPanel
|
|
|
- referencePrice={currentPrice}
|
|
|
- on:confirm={(e) => addOrder({ side: 'Venda', price: e.detail.price, amount: e.detail.amount, total: e.detail.total, status: 'Aberta', type: e.detail.type })}
|
|
|
- />
|
|
|
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
|
+ <div class="md:col-span-1">
|
|
|
+ <TabelaOrdens {ordensCompra} {ordensVenda} {ultimaVenda} />
|
|
|
+ </div>
|
|
|
+ <div class="md:col-span-2">
|
|
|
+ <GraficoCandlestick {dadosMock} />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
-
|
|
|
-<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
- <Tables title="Ordens de Compra (pendentes)" columns={orderColumns} data={displayPendingBuys} showActions={false} showAdd={false}/>
|
|
|
- <Tables title="Ordens de Venda (pendentes)" columns={orderColumns} data={displayPendingSells} showActions={false} showAdd={false}/>
|
|
|
-</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <BoletaCompra visible={showBuyModal} onClose={() => (showBuyModal = false)} state={selectedState} commodity={selectedCommodityLabel} />
|
|
|
+ <BoletaVenda visible={showSellModal} onClose={() => (showSellModal = false)} state={selectedState} commodity={selectedCommodityLabel} />
|
|
|
</div>
|