group offers by price

with a checkbox that allows showing each individual order
This commit is contained in:
wireless_purple 2024-10-12 20:27:22 +00:00
parent a921561083
commit 6bbc71ae39
8 changed files with 146 additions and 62 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -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"

View file

@ -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 {

View file

@ -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

View file

@ -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),

View file

@ -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

View 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>

View file

@ -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