From 1cf7ef55d573a529d388c8ce73b36313449a6d62 Mon Sep 17 00:00:00 2001 From: Victor Date: Tue, 17 Oct 2023 23:47:48 -0400 Subject: [PATCH 01/11] increased order book limit --- src/app/components/OrderBook.tsx | 8 +++++++- src/app/redux/orderBookSlice.ts | 5 ++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/app/components/OrderBook.tsx b/src/app/components/OrderBook.tsx index 959cf495..4cf8fbb2 100644 --- a/src/app/components/OrderBook.tsx +++ b/src/app/components/OrderBook.tsx @@ -115,6 +115,11 @@ export function OrderBook() { return (
+
+ + Orderbook + +
Order @@ -134,7 +139,8 @@ export function OrderBook() {
({token1Symbol})
- +
+
{sells.map((props, index) => ( ))} diff --git a/src/app/redux/orderBookSlice.ts b/src/app/redux/orderBookSlice.ts index 2187658b..916cc645 100644 --- a/src/app/redux/orderBookSlice.ts +++ b/src/app/redux/orderBookSlice.ts @@ -47,7 +47,7 @@ export function toOrderBookRowProps( adexRows.reverse(); barColor = "hsl(var(--erc))"; } - adexRows = adexRows.slice(0, 8); // Limit to 8 rows + adexRows = adexRows.slice(0, 11); // Limit to 8 rows let total = 0; let maxTotal = 0; @@ -70,7 +70,7 @@ export function toOrderBookRowProps( } // If there are fewer than 8 orders, fill the remaining rows with empty values - while (props.length < 8) { + while (props.length < 11) { props.push({ absentOrders: "\u00A0" }); } @@ -101,7 +101,6 @@ export const orderBookSlice = createSlice({ adexState.currentPairOrderbook.buys, "buy" ); - let bestSell = sells[sells.length - 1]?.price || null; let bestBuy = buys[0]?.price || null; From 393c6413fa744b7c810dc68794fe64aaaad0c1ab Mon Sep 17 00:00:00 2001 From: Victor Date: Wed, 18 Oct 2023 00:35:54 -0400 Subject: [PATCH 02/11] styling --- src/app/components/OrderBook.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/app/components/OrderBook.tsx b/src/app/components/OrderBook.tsx index 4cf8fbb2..ae5c14fa 100644 --- a/src/app/components/OrderBook.tsx +++ b/src/app/components/OrderBook.tsx @@ -114,13 +114,17 @@ export function OrderBook() { return (
-
-
- - Orderbook - +
+
Order book
+
+ Grouping: + + +
-
+
+
+
Order
From e4289a51b0e70e9f093fff72ec8a3fe58e0aefe9 Mon Sep 17 00:00:00 2001 From: Victor Date: Wed, 18 Oct 2023 00:39:35 -0400 Subject: [PATCH 03/11] fix tests --- __tests__/orderBookSlice.test.ts | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/__tests__/orderBookSlice.test.ts b/__tests__/orderBookSlice.test.ts index 8937f758..f1c97db8 100644 --- a/__tests__/orderBookSlice.test.ts +++ b/__tests__/orderBookSlice.test.ts @@ -5,6 +5,11 @@ import { } from "../src/app/redux/orderBookSlice"; const MOCK_SELLS = [ + new OrderbookLine(25, 1, 1, 1, 1, false), + new OrderbookLine(24, 1, 1, 1, 1, false), + new OrderbookLine(23, 1, 1, 1, 1, false), + new OrderbookLine(22, 1, 1, 1, 1, false), + new OrderbookLine(21, 1, 1, 1, 1, false), new OrderbookLine(20, 1, 1, 1, 1, false), new OrderbookLine(19, 1, 1, 1, 1, false), new OrderbookLine(18, 1, 1, 1, 1, false), @@ -12,12 +17,12 @@ const MOCK_SELLS = [ new OrderbookLine(16, 1, 1, 1, 1, false), new OrderbookLine(15, 1, 1, 1, 1, false), new OrderbookLine(14, 1, 1, 1, 1, false), - new OrderbookLine(13, 1, 1, 1, 1, false), - new OrderbookLine(12, 1, 1, 1, 1, false), - new OrderbookLine(11, 1, 1, 1, 1, false), ]; const MOCK_BUYS = [ + new OrderbookLine(13, 1, 1, 1, 1, false), + new OrderbookLine(12, 1, 1, 1, 1, false), + new OrderbookLine(11, 1, 1, 1, 1, false), new OrderbookLine(10, 1, 1, 1, 1, false), new OrderbookLine(9, 1, 1, 1, 1, false), new OrderbookLine(8, 1, 1, 1, 1, false), @@ -31,24 +36,24 @@ const MOCK_BUYS = [ ]; describe("toOrderBookRowProps", () => { - it("returns 8 rows if the input is empty", () => { + it("returns 11 rows if the input is empty", () => { const input: OrderbookLine[] = []; - expect(toOrderBookRowProps(input, "sell").length).toBe(8); + expect(toOrderBookRowProps(input, "sell").length).toBe(11); }); - it("returns 8 rows if the input is smaller", () => { + it("returns 11 rows if the input is smaller", () => { const input: OrderbookLine[] = MOCK_SELLS.slice(0, 5); - expect(toOrderBookRowProps(input, "sell").length).toBe(8); + expect(toOrderBookRowProps(input, "sell").length).toBe(11); }); - it("returns 8 rows if the input is larger", () => { - expect(toOrderBookRowProps(MOCK_SELLS, "sell").length).toBe(8); + it("returns 11 rows if the input is larger", () => { + expect(toOrderBookRowProps(MOCK_SELLS, "sell").length).toBe(11); }); it("drops the correct farther away rows for sells", () => { - const expectedSellPrices = [18, 17, 16, 15, 14, 13, 12, 11]; + const expectedSellPrices = [24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14]; const sellRowProps = toOrderBookRowProps(MOCK_SELLS, "sell"); @@ -58,7 +63,7 @@ describe("toOrderBookRowProps", () => { }); it("drops the correct farther away rows for buys", () => { - const expectedBuyPrices = [10, 9, 8, 7, 6, 5, 4, 3]; + const expectedBuyPrices = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3]; const buyRowProps = toOrderBookRowProps(MOCK_BUYS, "buy"); @@ -68,8 +73,8 @@ describe("toOrderBookRowProps", () => { }); it("calculates correct totals", () => { - const expectedSellTotals = [8, 7, 6, 5, 4, 3, 2, 1]; - const expectedBuyTotals = [1, 2, 3, 4, 5, 6, 7, 8]; + const expectedSellTotals = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; + const expectedBuyTotals = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; const sellRowProps = toOrderBookRowProps(MOCK_SELLS, "sell"); const buyRowProps = toOrderBookRowProps(MOCK_BUYS, "buy"); From 9b6df19323cc9aed2831c69dcfec1698bcbf5019 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 19 Oct 2023 23:58:37 -0400 Subject: [PATCH 04/11] input working --- src/app/components/OrderBook.tsx | 20 ++++++++----- src/app/redux/orderBookSlice.ts | 50 ++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/app/components/OrderBook.tsx b/src/app/components/OrderBook.tsx index ae5c14fa..12d26138 100644 --- a/src/app/components/OrderBook.tsx +++ b/src/app/components/OrderBook.tsx @@ -1,8 +1,8 @@ import { CSSProperties } from "react"; import "../styles/orderbook.css"; import * as utils from "../utils"; -import { OrderBookRowProps } from "../redux/orderBookSlice"; -import { useAppSelector } from "../hooks"; +import { OrderBookRowProps, orderBookSlice } from "../redux/orderBookSlice"; +import { useAppDispatch, useAppSelector } from "../hooks"; function OrderBookRow(props: OrderBookRowProps) { const { barColor, orderCount, price, size, total, maxTotal } = props; @@ -103,6 +103,7 @@ function CurrentPriceRow() { } export function OrderBook() { + const dispatch = useAppDispatch(); const token1Symbol = useAppSelector( (state) => state.pairSelector.token1.symbol ); @@ -111,16 +112,21 @@ export function OrderBook() { ); const sells = useAppSelector((state) => state.orderBook.sells); const buys = useAppSelector((state) => state.orderBook.buys); + //const grouping = useAppSelector((state) => state.orderBook.grouping); return (
Order book
-
- Grouping: - - - +
+ Grouping + ) => { + const grouping = Number(event.target.value); + dispatch(orderBookSlice.actions.setGrouping(grouping)); + }} + >
diff --git a/src/app/redux/orderBookSlice.ts b/src/app/redux/orderBookSlice.ts index 916cc645..28bca013 100644 --- a/src/app/redux/orderBookSlice.ts +++ b/src/app/redux/orderBookSlice.ts @@ -20,6 +20,7 @@ export interface OrderBookState { bestBuy: number | null; spread: number | null; spreadPercent: number | null; + grouping: number | null; } const initialState: OrderBookState = { @@ -30,11 +31,13 @@ const initialState: OrderBookState = { bestBuy: null, spread: null, spreadPercent: null, + grouping: 0, }; export function toOrderBookRowProps( adexOrderbookLines: adex.OrderbookLine[], - side: "sell" | "buy" + side: "sell" | "buy", + grouping: number ): OrderBookRowProps[] { // this will drop the rows that do not fit into 8 buys/sells // TODO: implement pagination or scrolling @@ -47,6 +50,31 @@ export function toOrderBookRowProps( adexRows.reverse(); barColor = "hsl(var(--erc))"; } + //console.log(adexRows); + //group the by the grouping amount + //console.log(grouping); + + const groupedArray = adexRows.reduce((result, item) => { + const existingItem: adex.OrderbookLine = result.find( + (x: adex.OrderbookLine) => x.price === item.price + ); + //if (existingItem === undefined) return result; + if (existingItem) { + // If an item with the same price exists, aggregate the values + existingItem.quantityRemaining += item.quantityRemaining; + existingItem.valueRemaining += item.valueRemaining; + existingItem.noOrders += item.noOrders; + existingItem.orders = existingItem.orders.concat(item.orders); + existingItem.total += item.total; + } else { + // If it's a new price, add it to the result + result.push({ ...item }); + } + + return result; + }, []); + console.log(groupedArray); + adexRows = adexRows.slice(0, 11); // Limit to 8 rows let total = 0; @@ -93,13 +121,17 @@ export const orderBookSlice = createSlice({ reducers: { updateAdex(state: OrderBookState, action: PayloadAction) { const adexState = action.payload; + const grouping = state.grouping; + const sells = toOrderBookRowProps( adexState.currentPairOrderbook.sells, - "sell" + "sell", + grouping || 0 ); const buys = toOrderBookRowProps( adexState.currentPairOrderbook.buys, - "buy" + "buy", + grouping || 0 ); let bestSell = sells[sells.length - 1]?.price || null; let bestBuy = buys[0]?.price || null; @@ -119,8 +151,20 @@ export const orderBookSlice = createSlice({ state.bestSell = bestSell; state.bestBuy = bestBuy; }, + setGrouping(state, action: PayloadAction) { + state.grouping = action.payload; + setFromGrouping(state); + }, }, }); +function setFromGrouping(state: OrderBookState) { + if (state.grouping === null) { + state.grouping = 0; + } else if (state.grouping < 0) { + state.grouping = 0; + } +} + export const selectBestBuy = (state: RootState) => state.orderBook.bestBuy; export const selectBestSell = (state: RootState) => state.orderBook.bestSell; From e6beae3d042103f35f789464f87ea34d108f0065 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 22 Oct 2023 14:43:00 -0400 Subject: [PATCH 05/11] working grouping --- src/app/redux/orderBookSlice.ts | 57 +++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src/app/redux/orderBookSlice.ts b/src/app/redux/orderBookSlice.ts index 28bca013..a43b86cc 100644 --- a/src/app/redux/orderBookSlice.ts +++ b/src/app/redux/orderBookSlice.ts @@ -52,31 +52,40 @@ export function toOrderBookRowProps( } //console.log(adexRows); //group the by the grouping amount - //console.log(grouping); - - const groupedArray = adexRows.reduce((result, item) => { - const existingItem: adex.OrderbookLine = result.find( - (x: adex.OrderbookLine) => x.price === item.price - ); - //if (existingItem === undefined) return result; - if (existingItem) { - // If an item with the same price exists, aggregate the values - existingItem.quantityRemaining += item.quantityRemaining; - existingItem.valueRemaining += item.valueRemaining; - existingItem.noOrders += item.noOrders; - existingItem.orders = existingItem.orders.concat(item.orders); - existingItem.total += item.total; - } else { - // If it's a new price, add it to the result - result.push({ ...item }); + console.log("grouping %d", grouping); + let groupedArray; + if (grouping > 0) { + const roundToGroup = (num: number) => Math.round(num / grouping) * grouping; + + if (adexRows.length > 0) { + groupedArray = adexRows.reduce((result: adex.OrderbookLine[], item) => { + const key = roundToGroup(item.price); + const foundItem = result.find( + (x: adex.OrderbookLine) => x.price === key + ); // note that we don't specify the type here + let existingItem: adex.OrderbookLine; // declare the variable without assigning it + if (foundItem !== undefined) { + // if the foundItem is not undefined, we can assign it safely + existingItem = foundItem; + existingItem.quantityRemaining += item.quantityRemaining; + existingItem.valueRemaining += item.valueRemaining; + existingItem.noOrders += item.noOrders; + existingItem.orders = existingItem.orders.concat(item.orders); + existingItem.total += item.total; + } else { + // If it's a new price, add it to the result + item.price = key; + result.push({ ...item }); + } + return result; + }, []); } - - return result; - }, []); - console.log(groupedArray); - - adexRows = adexRows.slice(0, 11); // Limit to 8 rows - + } + if (groupedArray != null) { + adexRows = groupedArray.slice(0, 11); //adexRows.slice(0, 11); // Limit to 8 rows + } else { + adexRows = adexRows.slice(0, 11); + } let total = 0; let maxTotal = 0; for (let adexRow of adexRows) { From 58d7e565e6ca614a551ba255513643181ad3f0c6 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 22 Oct 2023 16:38:43 -0400 Subject: [PATCH 06/11] updating grouping on edit --- src/app/redux/orderBookSlice.ts | 47 ++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/src/app/redux/orderBookSlice.ts b/src/app/redux/orderBookSlice.ts index a43b86cc..ac18f32b 100644 --- a/src/app/redux/orderBookSlice.ts +++ b/src/app/redux/orderBookSlice.ts @@ -130,6 +130,7 @@ export const orderBookSlice = createSlice({ reducers: { updateAdex(state: OrderBookState, action: PayloadAction) { const adexState = action.payload; + console.log(adexState); const grouping = state.grouping; const sells = toOrderBookRowProps( @@ -161,19 +162,45 @@ export const orderBookSlice = createSlice({ state.bestBuy = bestBuy; }, setGrouping(state, action: PayloadAction) { - state.grouping = action.payload; - setFromGrouping(state); + if (action.payload === null) { + state.grouping = 0; + } else if (action.payload < 0) { + state.grouping = 0; + } else { + state.grouping = action.payload; + } + + const sells = toOrderBookRowProps( + adex.clientState.currentPairOrderbook.sells, + "sell", + state.grouping || 0 + ); + const buys = toOrderBookRowProps( + adex.clientState.currentPairOrderbook.buys, + "buy", + state.grouping || 0 + ); + + let bestSell = sells[sells.length - 1]?.price || null; + let bestBuy = buys[0]?.price || null; + + if (bestBuy !== null && bestSell !== null) { + const spread = bestSell - bestBuy; + if (bestBuy + bestSell !== 0) { + const spreadPercent = ((2 * spread) / (bestBuy + bestSell)) * 100; + state.spreadPercent = spreadPercent; + } + state.spread = spread; + } + + state.sells = sells; + state.buys = buys; + state.lastPrice = adex.clientState.currentPairInfo.lastPrice; + state.bestSell = bestSell; + state.bestBuy = bestBuy; }, }, }); -function setFromGrouping(state: OrderBookState) { - if (state.grouping === null) { - state.grouping = 0; - } else if (state.grouping < 0) { - state.grouping = 0; - } -} - export const selectBestBuy = (state: RootState) => state.orderBook.bestBuy; export const selectBestSell = (state: RootState) => state.orderBook.bestSell; From b1939660a726f9eb4428e525e13376f45a2d4f45 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 22 Oct 2023 16:45:07 -0400 Subject: [PATCH 07/11] fixed merge conflict --- src/app/components/OrderBook.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app/components/OrderBook.tsx b/src/app/components/OrderBook.tsx index 9335330c..0de976e4 100644 --- a/src/app/components/OrderBook.tsx +++ b/src/app/components/OrderBook.tsx @@ -1,7 +1,5 @@ import { CSSProperties } from "react"; -import { useAppSelector } from "../hooks"; -import { OrderBookRowProps } from "../redux/orderBookSlice"; import "../styles/orderbook.css"; import * as utils from "../utils"; import { OrderBookRowProps, orderBookSlice } from "../redux/orderBookSlice"; From 24c0b78ffcb81b940434b43fdec0ff866126c1a6 Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 23 Oct 2023 18:23:05 -0400 Subject: [PATCH 08/11] cleaned up logs --- src/app/redux/orderBookSlice.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/app/redux/orderBookSlice.ts b/src/app/redux/orderBookSlice.ts index ac18f32b..c745ae32 100644 --- a/src/app/redux/orderBookSlice.ts +++ b/src/app/redux/orderBookSlice.ts @@ -50,9 +50,6 @@ export function toOrderBookRowProps( adexRows.reverse(); barColor = "hsl(var(--erc))"; } - //console.log(adexRows); - //group the by the grouping amount - console.log("grouping %d", grouping); let groupedArray; if (grouping > 0) { const roundToGroup = (num: number) => Math.round(num / grouping) * grouping; @@ -130,7 +127,6 @@ export const orderBookSlice = createSlice({ reducers: { updateAdex(state: OrderBookState, action: PayloadAction) { const adexState = action.payload; - console.log(adexState); const grouping = state.grouping; const sells = toOrderBookRowProps( From de036162bc76ee957ad096679cb626f4625084ec Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 23 Oct 2023 18:24:40 -0400 Subject: [PATCH 09/11] corrected comments --- src/app/redux/orderBookSlice.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/app/redux/orderBookSlice.ts b/src/app/redux/orderBookSlice.ts index c745ae32..eec8c3e6 100644 --- a/src/app/redux/orderBookSlice.ts +++ b/src/app/redux/orderBookSlice.ts @@ -39,9 +39,6 @@ export function toOrderBookRowProps( side: "sell" | "buy", grouping: number ): OrderBookRowProps[] { - // this will drop the rows that do not fit into 8 buys/sells - // TODO: implement pagination or scrolling - const props: OrderBookRowProps[] = []; let adexRows = [...adexOrderbookLines]; // copy the array so we can mutate it @@ -79,7 +76,7 @@ export function toOrderBookRowProps( } } if (groupedArray != null) { - adexRows = groupedArray.slice(0, 11); //adexRows.slice(0, 11); // Limit to 8 rows + adexRows = groupedArray.slice(0, 11); //adexRows.slice(0, 11); // Limit to 11 rows } else { adexRows = adexRows.slice(0, 11); } @@ -103,7 +100,7 @@ export function toOrderBookRowProps( props[i].maxTotal = maxTotal; } - // If there are fewer than 8 orders, fill the remaining rows with empty values + // If there are fewer than 11 orders, fill the remaining rows with empty values while (props.length < 11) { props.push({ absentOrders: "\u00A0" }); } From e28acbb86dd6983f3eadaca1a08fd2a6088d0707 Mon Sep 17 00:00:00 2001 From: Evgeniia Vakarina <27793901+EvgeniiaVak@users.noreply.github.com> Date: Wed, 25 Oct 2023 21:35:15 +0400 Subject: [PATCH 10/11] default post only disabled --- src/app/redux/orderInputSlice.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/redux/orderInputSlice.ts b/src/app/redux/orderInputSlice.ts index f48de435..76dc4862 100644 --- a/src/app/redux/orderInputSlice.ts +++ b/src/app/redux/orderInputSlice.ts @@ -89,7 +89,7 @@ export const initialState: OrderInputState = { token2: initialTokenInput, validationToken2: initialValidationResult, tab: OrderTab.MARKET, - postOnly: true, + postOnly: false, side: adex.OrderSide.BUY, price: 0, slippage: 0.01, From 0ccbeed149f3457fbd1ceacd95f28924bfefa0ae Mon Sep 17 00:00:00 2001 From: Evgeniia Vakarina <27793901+EvgeniiaVak@users.noreply.github.com> Date: Wed, 25 Oct 2023 21:35:43 +0400 Subject: [PATCH 11/11] update postonly tooltip --- src/app/components/order_input/LimitOrderInput.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/components/order_input/LimitOrderInput.tsx b/src/app/components/order_input/LimitOrderInput.tsx index 8133de0d..da8a95a3 100644 --- a/src/app/components/order_input/LimitOrderInput.tsx +++ b/src/app/components/order_input/LimitOrderInput.tsx @@ -18,9 +18,9 @@ import { AiOutlineInfoCircle } from "react-icons/ai"; import { BottomRightErrorLabel } from "components/BottomRightErrorLabel"; const POST_ONLY_TOOLTIP = - "If your price is very close to the current market price, your limit order might fill immediately, " + - "making you pay taker fees. This option prevents your order from being executed immediately, " + - "guarantees that your order will make it to the order book and you will earn the liquidity provider fees."; + "Select 'POST ONLY' to ensure your order is added to the order book without matching existing orders. " + + "If your order can be partially or completely executed immediately, it will not be created. " + + "This option removes trading fees completely and ensures you receive the maker rebate."; function NonTargetToken() { const { token2, validationToken2, side } = useAppSelector( @@ -246,7 +246,7 @@ export function LimitOrderInput() { POST ONLY