group offers by price
with a checkbox that allows showing each individual order
This commit is contained in:
parent
a921561083
commit
6bbc71ae39
8 changed files with 146 additions and 62 deletions
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
12
package.json
12
package.json
|
@ -11,12 +11,12 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.3",
|
||||
"@sveltejs/kit": "^2.6.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.7",
|
||||
"prettier": "^3.3.2",
|
||||
"prettier-plugin-svelte": "^3.2.5",
|
||||
"sass": "^1.79.4",
|
||||
"svelte": "^5.0.0-next.262",
|
||||
"@sveltejs/kit": "^2.7.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.8",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-svelte": "^3.2.7",
|
||||
"sass": "^1.79.5",
|
||||
"svelte": "^5.0.0-next.264",
|
||||
"svelte-adapter-bun": "^0.5.2",
|
||||
"svelte-preprocess": "^6.0.3",
|
||||
"vite": "^5.4.8"
|
||||
|
|
|
@ -67,6 +67,9 @@ Object.groupBy ||= (values, keyFinder) => {
|
|||
</div>
|
||||
|
||||
<style lang="scss" global>
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.app {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
@ -127,7 +130,7 @@ Object.groupBy ||= (values, keyFinder) => {
|
|||
td:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
tbody tr:nth-child(2n) {
|
||||
tbody tr:nth-child(2n + 1) {
|
||||
background-color: #0002;
|
||||
}
|
||||
tfoot {
|
||||
|
|
|
@ -190,12 +190,14 @@ let w = $state();
|
|||
<div class="card col">
|
||||
<h4>Markets</h4>
|
||||
<table>
|
||||
<tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Currency</th>
|
||||
<th>Price</th>
|
||||
<th>Trades</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each Object.values(Object.groupBy(data.trades, ({ currency }) => currency))
|
||||
.toSorted((a, b) => b.length - a.length || (b[0].currency < a[0].currency ? 1 : -1))
|
||||
.slice(0, 16) as market}
|
||||
|
@ -223,12 +225,14 @@ let w = $state();
|
|||
<div class="card col">
|
||||
<h4>Trades</h4>
|
||||
<table>
|
||||
<tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Amount (XMR)</th>
|
||||
<th>Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each data.trades.slice(0, 16) as trade}
|
||||
<tr>
|
||||
<td
|
||||
|
|
|
@ -8,6 +8,12 @@ export async function load({ params }) {
|
|||
get(offers)[params.market],
|
||||
({ direction }) => direction,
|
||||
);
|
||||
groupedOffers.BUY = groupedOffers.BUY
|
||||
? Object.groupBy(groupedOffers.BUY, ({ price }) => price)
|
||||
: [];
|
||||
groupedOffers.SELL = groupedOffers.SELL
|
||||
? Object.groupBy(groupedOffers.SELL, ({ price }) => price)
|
||||
: [];
|
||||
}
|
||||
return {
|
||||
trades: get(trades).filter(({ currency }) => currency === params.market),
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
isMoneroQuote,
|
||||
} from "$lib/formatPrice";
|
||||
import { CandlestickSeries, Chart, TimeScale } from "svelte-lightweight-charts";
|
||||
import Offers from "./Offers.svelte";
|
||||
|
||||
const market = $page.params.market;
|
||||
let { data } = $props();
|
||||
|
@ -66,6 +67,8 @@ const gridLayout = {
|
|||
|
||||
const marketPair = isMoneroQuote(market) ? `${market}/XMR` : `XMR/${market}`;
|
||||
const BUY_SELL = isMoneroQuote(market) ? ["SELL", "BUY"] : ["BUY", "SELL"];
|
||||
|
||||
let showOrders = $state(false);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -96,70 +99,41 @@ const BUY_SELL = isMoneroQuote(market) ? ["SELL", "BUY"] : ["BUY", "SELL"];
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col card">
|
||||
<h4>Buy Offers</h4>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Price</th>
|
||||
<th>Amount (XMR)</th>
|
||||
<th>Amount ({market})</th>
|
||||
</tr>
|
||||
{#each data.offers[BUY_SELL[0]]?.toSorted((a, b) => b.price - a.price) || [] as offer}
|
||||
<tr title={offer.paymentMethod}>
|
||||
<td>{formatPrice(offer.price, market, false, false)}</td>
|
||||
<td>{formatPrice(offer.amount, "XMR", false, false)}</td>
|
||||
<td
|
||||
>{formatPrice(
|
||||
offer.primaryMarketAmount,
|
||||
market,
|
||||
false,
|
||||
false,
|
||||
)}</td
|
||||
>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col card">
|
||||
<h4>Sell Offers</h4>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Price</th>
|
||||
<th>Amount (XMR)</th>
|
||||
<th>Amount ({market})</th>
|
||||
</tr>
|
||||
{#each data.offers[BUY_SELL[1]]?.toSorted((a, b) => a.price - b.price) || [] as offer}
|
||||
<tr title={offer.paymentMethod}>
|
||||
<td>{formatPrice(offer.price, market, false, false)}</td>
|
||||
<td>{formatPrice(offer.amount, "XMR", false, false)}</td>
|
||||
<td
|
||||
>{formatPrice(
|
||||
offer.primaryMarketAmount,
|
||||
market,
|
||||
false,
|
||||
false,
|
||||
)}</td
|
||||
>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
<Offers
|
||||
offers={Object.values(data.offers[BUY_SELL[0]])?.toSorted(
|
||||
(a, b) => b[0].price - a[0].price,
|
||||
)}
|
||||
{market}
|
||||
title="Buy Offers"
|
||||
{showOrders}
|
||||
/>
|
||||
<Offers
|
||||
offers={Object.values(data.offers[BUY_SELL[1]])?.toSorted(
|
||||
(a, b) => a[0].price - b[0].price,
|
||||
)}
|
||||
{market}
|
||||
title="Sell Offers"
|
||||
{showOrders}
|
||||
/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<input type="checkbox" bind:checked={showOrders} />Show Individual Offers?
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col card">
|
||||
<h4>Latest Trades</h4>
|
||||
<table>
|
||||
<tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Price</th>
|
||||
<th>Amount (XMR)</th>
|
||||
<th>Amount ({market})</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each data.trades as trade}
|
||||
<tr>
|
||||
<td
|
||||
|
|
95
src/routes/market/[market]/Offers.svelte
Normal file
95
src/routes/market/[market]/Offers.svelte
Normal file
|
@ -0,0 +1,95 @@
|
|||
<svelte:options runes={true} />
|
||||
|
||||
<script>
|
||||
import { formatPrice } from "$lib/formatPrice";
|
||||
|
||||
let { offers = [], market, title, showOrders } = $props();
|
||||
offers = Object.values(offers);
|
||||
</script>
|
||||
|
||||
<div class="col card" style="--text-align: {showOrders ? 'left' : 'right'}">
|
||||
<h4>{title}</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Price</th>
|
||||
{#if showOrders}<th>Payment Method</th>{/if}
|
||||
<th>Amount (XMR)</th>
|
||||
<th>Amount ({market})</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#if !showOrders}
|
||||
{#each offers as offer}
|
||||
<tr>
|
||||
<td>{formatPrice(offer[0].price, market, false, false)}</td>
|
||||
<td
|
||||
>{formatPrice(
|
||||
offer.reduce((a, b) => a + b.amount, 0),
|
||||
"XMR",
|
||||
false,
|
||||
false,
|
||||
)}</td
|
||||
>
|
||||
<td
|
||||
>{formatPrice(
|
||||
offer.reduce((a, b) => a + b.primaryMarketAmount, 0),
|
||||
market,
|
||||
false,
|
||||
false,
|
||||
)}</td
|
||||
>
|
||||
</tr>
|
||||
{/each}
|
||||
{:else}
|
||||
{#each offers.flat() as offer}
|
||||
<tr>
|
||||
<td>{formatPrice(offer.price, market, false, false)}</td>
|
||||
{#if showOrders}<td>{offer.paymentMethod}</td>{/if}
|
||||
<td>{formatPrice(offer.amount, "XMR", false, false)}</td>
|
||||
<td
|
||||
>{formatPrice(
|
||||
offer.primaryMarketAmount,
|
||||
market,
|
||||
false,
|
||||
false,
|
||||
)}</td
|
||||
>
|
||||
</tr>
|
||||
{/each}
|
||||
{/if}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td>{offers.flat().reduce((a, b) => a + 1, 0)} Offers</td>
|
||||
|
||||
{#if showOrders}<td></td>{/if}
|
||||
<td
|
||||
>{formatPrice(
|
||||
offers.flat().reduce((a, b) => a + b.amount, 0),
|
||||
"XMR",
|
||||
false,
|
||||
false,
|
||||
) || ""}</td
|
||||
>
|
||||
<td
|
||||
>{formatPrice(
|
||||
offers.flat().reduce((a, b) => a + b.primaryMarketAmount, 0),
|
||||
market,
|
||||
false,
|
||||
false,
|
||||
) || ""}</td
|
||||
>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
td,
|
||||
th {
|
||||
&:nth-child(2) {
|
||||
text-align: var(--text-align);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -124,7 +124,7 @@ let w = $state();
|
|||
<div class="card col">
|
||||
<h4>Markets</h4>
|
||||
<table>
|
||||
<tbody>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Currency</th>
|
||||
<th>Price</th>
|
||||
|
@ -132,6 +132,8 @@ let w = $state();
|
|||
<th>Volume (XMR)</th>
|
||||
<th>Trades</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each Object.values(markets).toSorted((a, b) => (b.trades?.length || 0) - (a.trades?.length || 0) || (b.offers?.length || 0) - (a.offers?.length || 0) || (b.code < a.code ? 1 : -1)) as market}
|
||||
<tr>
|
||||
<td
|
||||
|
|
Loading…
Reference in a new issue