Merge pull request #20 from hyle-team/feature/add-get-user-orders-pagination

feat: add get-user-orders pagination
This commit is contained in:
Dmitrii Kolpakov 2026-02-18 21:08:31 +07:00 committed by GitHub
commit bfae676c2e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 782 additions and 27 deletions

View file

@ -2,11 +2,27 @@ import { Request, Response } from 'express';
import Decimal from 'decimal.js';
import CreateOrderRes, { CreateOrderErrorCode } from '@/interfaces/responses/orders/CreateOrderRes';
import GetUserOrdersRes, {
GetUserOrdersErrorCode,
GetUserOrdersResCurrency,
GetUserOrdersResOrderData,
} from '@/interfaces/responses/orders/GetUserOrdersRes';
import GetUserOrdersAllPairsBody from '@/interfaces/bodies/orders/GetUserOrdersAllPairsBody';
import GetUserOrdersAllPairsRes, {
GetUserOrdersAllPairsErrorCode,
GetUserOrdersAllPairsResPair,
} from '@/interfaces/responses/orders/GetUserOrdersAllPairsRes';
import CancelAllBody, { CancelAllBodyOrderType } from '@/interfaces/bodies/orders/CancelAllBody';
import sequelize from '@/sequelize';
import CancelAllRes, { CancelAllErrorCode } from '@/interfaces/responses/orders/CancelAllRes';
import candlesModel from '../models/Candles';
import ordersModel from '../models/Orders';
import CreateOrderBody from '../interfaces/bodies/orders/CreateOrderBody';
import GetUserOrdersPageBody from '../interfaces/bodies/orders/GetUserOrdersPageBody';
import GetUserOrdersBody from '../interfaces/bodies/orders/GetUserOrdersBody';
import GetUserOrdersBody, {
GetUserOrdersBodyStatus,
GetUserOrdersBodyType,
} from '../interfaces/bodies/orders/GetUserOrdersBody';
import CancelOrderBody from '../interfaces/bodies/orders/CancelOrderBody';
import GetCandlesBody from '../interfaces/bodies/orders/GetCandlesBody';
import GetChartOrdersBody from '../interfaces/bodies/orders/GetChartOrdersBody';
@ -157,21 +173,171 @@ class OrdersController {
}
}
async getUserOrders(req: Request, res: Response) {
private fromGetUserOrdersServiceToResCurrencyMapper(
currency: Currency,
): GetUserOrdersResCurrency {
return {
id: currency.id,
name: currency.name,
code: currency.code,
type: currency.type,
asset_id: currency.asset_id,
auto_parsed: currency.auto_parsed,
asset_info: currency.asset_info
? {
asset_id: currency.asset_info.asset_id,
logo: currency.asset_info.logo,
price_url: currency.asset_info.price_url,
ticker: currency.asset_info.ticker,
full_name: currency.asset_info.full_name,
total_max_supply: currency.asset_info.total_max_supply,
current_supply: currency.asset_info.current_supply,
decimal_point: currency.asset_info.decimal_point,
meta_info: currency.asset_info.meta_info,
}
: undefined,
whitelisted: currency.whitelisted,
};
}
getUserOrders = async (req: Request, res: Response<GetUserOrdersRes>) => {
try {
await userModel.resetExchangeNotificationsAmount(
(req.body.userData as UserData).address,
);
const result = await ordersModel.getUserOrders(req.body as GetUserOrdersBody);
const body = req.body as GetUserOrdersBody;
const { userData, offset, limit, filterInfo } = body;
if (result.data === 'Internal error') return res.status(500).send(result);
await userModel.resetExchangeNotificationsAmount(userData.address);
res.status(200).send(result);
const serviceOrderType: 'buy' | 'sell' | undefined = (() => {
if (filterInfo?.type === undefined) {
return undefined;
}
return filterInfo.type === GetUserOrdersBodyType.BUY ? 'buy' : 'sell';
})();
const serviceOrderStatus: 'active' | 'finished' | undefined = (() => {
if (filterInfo?.status === undefined) {
return undefined;
}
return filterInfo.status === GetUserOrdersBodyStatus.ACTIVE ? 'active' : 'finished';
})();
const result = await ordersModel.getUserOrders({
address: userData.address,
offset,
limit,
filterInfo: {
pairId: filterInfo.pairId,
type: serviceOrderType,
status: serviceOrderStatus,
date:
filterInfo.date !== undefined
? {
from: filterInfo.date.from,
to: filterInfo.date.to,
}
: undefined,
},
});
if (result.data === 'Internal error') {
throw new Error('ordersModel.getUserOrders returned Internal error');
}
const { totalItemsCount } = result;
const userOrders = result.data.map((order) => {
const mappedOrder: GetUserOrdersResOrderData = {
id: order.id,
type: order.type,
timestamp: order.timestamp,
side: order.side,
price: order.price,
amount: order.amount,
total: order.total,
pair_id: order.pair_id,
user_id: order.user_id,
status: order.status,
left: order.left,
hasNotification: order.hasNotification,
pair: {
id: order.pair.id,
first_currency_id: order.pair.first_currency_id,
second_currency_id: order.pair.second_currency_id,
rate: order.pair.rate,
coefficient: order.pair.coefficient,
high: order.pair.high,
low: order.pair.low,
volume: order.pair.volume,
featured: order.pair.featured,
first_currency: this.fromGetUserOrdersServiceToResCurrencyMapper(
order.pair.first_currency,
),
second_currency: this.fromGetUserOrdersServiceToResCurrencyMapper(
order.pair.second_currency,
),
},
first_currency: this.fromGetUserOrdersServiceToResCurrencyMapper(
order.first_currency,
),
second_currency: this.fromGetUserOrdersServiceToResCurrencyMapper(
order.second_currency,
),
isInstant: order.isInstant,
};
return mappedOrder;
});
res.status(200).send({
success: true,
totalItemsCount,
data: userOrders,
});
} catch (err) {
console.log(err);
res.status(500).send({ success: false, data: 'Unhandled error' });
res.status(500).send({
success: false,
data: GetUserOrdersErrorCode.UNHANDLED_ERROR,
});
}
};
getUserOrdersAllPairs = async (req: Request, res: Response<GetUserOrdersAllPairsRes>) => {
try {
const body = req.body as GetUserOrdersAllPairsBody;
const { userData } = body;
const getUserOrdersAllPairsResult = await ordersModel.getUserOrdersAllPairs(
userData.address,
);
const pairs = getUserOrdersAllPairsResult.data;
const responsePairs: GetUserOrdersAllPairsResPair[] = pairs.map((pair) => ({
id: pair.id,
firstCurrency: {
id: pair.firstCurrency.id,
ticker: pair.firstCurrency.ticker,
},
secondCurrency: {
id: pair.secondCurrency.id,
ticker: pair.secondCurrency.ticker,
},
}));
res.status(200).send({
success: true,
data: responsePairs,
});
} catch (err) {
console.log(err);
res.status(500).send({
success: false,
data: GetUserOrdersAllPairsErrorCode.UNHANDLED_ERROR,
});
}
};
async cancelOrder(req: Request, res: Response) {
try {
@ -289,6 +455,51 @@ class OrdersController {
res.status(500).send({ success: false, data: 'Unhandled error' });
}
}
async cancelAll(req: Request, res: Response<CancelAllRes>) {
try {
const body = req.body as CancelAllBody;
const { userData, filterInfo } = body;
const filterType = (() => {
if (filterInfo.type === undefined) {
return undefined;
}
return filterInfo.type === CancelAllBodyOrderType.BUY
? GetUserOrdersBodyType.BUY
: GetUserOrdersBodyType.SELL;
})();
await sequelize.transaction(async (transaction) => {
await ordersModel.cancelAll(
{
address: userData.address,
filterInfo: {
pairId: filterInfo.pairId,
type: filterType,
date:
filterInfo.date !== undefined
? {
from: filterInfo.date.from,
to: filterInfo.date.to,
}
: undefined,
},
},
{ transaction },
);
});
res.status(200).send({ success: true });
} catch (err) {
console.log(err);
res.status(500).send({
success: false,
data: CancelAllErrorCode.UNHANDLED_ERROR,
});
}
}
}
const ordersController = new OrdersController();

View file

@ -0,0 +1,50 @@
import UserData from '@/interfaces/common/UserData';
import { body } from 'express-validator';
export enum CancelAllBodyOrderType {
// eslint-disable-next-line no-unused-vars
BUY = 'buy',
// eslint-disable-next-line no-unused-vars
SELL = 'sell',
}
interface CancelAllBody {
userData: UserData;
filterInfo: {
pairId?: number;
type?: CancelAllBodyOrderType;
date?: {
// UNIX timestamps in milliseconds
from: number;
to: number;
};
};
}
export const cancelAllValidator = [
body('filterInfo').isObject().withMessage('filterInfo must be an object'),
body('filterInfo.pairId')
.optional()
.isInt({ min: 0 })
.withMessage('filterInfo.pairId must be a non-negative integer'),
body('filterInfo.type')
.optional()
.isIn(Object.values(CancelAllBodyOrderType))
.withMessage(`Invalid filterInfo.type value`),
body('filterInfo.date').optional().isObject().withMessage('filterInfo.date must be an object'),
body('filterInfo.date.from')
.if(body('filterInfo.date').isObject())
.isInt({ min: 0 })
.withMessage(
'filterInfo.date.from must be a non-negative integer representing a UNIX timestamp in milliseconds',
),
body('filterInfo.date.to')
.if(body('filterInfo.date').isObject())
.isInt({ min: 0 })
.withMessage(
'filterInfo.date.to must be a non-negative integer representing a UNIX timestamp in milliseconds',
),
];
export default CancelAllBody;

View file

@ -0,0 +1,9 @@
import UserData from '@/interfaces/common/UserData';
interface GetUserOrdersAllPairsBody {
userData: UserData;
}
export const getUserOrdersAllPairsValidator = [];
export default GetUserOrdersAllPairsBody;

View file

@ -1,7 +1,68 @@
import UserData from '../../common/UserData';
import UserData from '@/interfaces/common/UserData';
import { body } from 'express-validator';
export enum GetUserOrdersBodyStatus {
// eslint-disable-next-line no-unused-vars
ACTIVE = 'active',
// eslint-disable-next-line no-unused-vars
FINISHED = 'finished',
}
export enum GetUserOrdersBodyType {
// eslint-disable-next-line no-unused-vars
BUY = 'buy',
// eslint-disable-next-line no-unused-vars
SELL = 'sell',
}
interface GetUserOrdersBody {
userData: UserData;
limit: number;
offset: number;
filterInfo: {
pairId?: number;
status?: GetUserOrdersBodyStatus;
type?: GetUserOrdersBodyType;
date?: {
// UNIX timestamps in milliseconds
from: number;
to: number;
};
};
}
export const getUserOrdersValidator = [
body('limit')
.isInt({ min: 1, max: 1000 })
.withMessage('limit must be a positive integer within certain range'),
body('offset').isInt({ min: 0 }).withMessage('offset must be a non-negative integer'),
body('filterInfo').isObject().withMessage('filterInfo must be an object'),
body('filterInfo.pairId')
.optional()
.isInt({ min: 0 })
.withMessage('filterInfo.pairId must be a non-negative integer'),
body('filterInfo.status')
.optional()
.isIn(Object.values(GetUserOrdersBodyStatus))
.withMessage(`Invalid filterInfo.status value`),
body('filterInfo.type')
.optional()
.isIn(Object.values(GetUserOrdersBodyType))
.withMessage(`Invalid filterInfo.type value`),
body('filterInfo.date').optional().isObject().withMessage('filterInfo.date must be an object'),
body('filterInfo.date.from')
.if(body('filterInfo.date').isObject())
.isInt({ min: 0 })
.withMessage(
'filterInfo.date.from must be a non-negative integer representing a UNIX timestamp in milliseconds',
),
body('filterInfo.date.to')
.if(body('filterInfo.date').isObject())
.isInt({ min: 0 })
.withMessage(
'filterInfo.date.to must be a non-negative integer representing a UNIX timestamp in milliseconds',
),
];
export default GetUserOrdersBody;

View file

@ -32,3 +32,7 @@ export interface PairWithCurrencies extends Pair {
export interface OrderWithPairAndCurrencies extends Order {
pair: PairWithCurrencies;
}
export interface PairWithIdAndCurrencies extends PairWithCurrencies {
id: number;
}

View file

@ -0,0 +1,17 @@
export type CancelAllSuccessRes = {
success: true;
};
export enum CancelAllErrorCode {
// eslint-disable-next-line no-unused-vars
UNHANDLED_ERROR = 'Unhandled error',
}
export type CancelAllErrorRes = {
success: false;
data: CancelAllErrorCode;
};
type CancelAllRes = CancelAllSuccessRes | CancelAllErrorRes;
export default CancelAllRes;

View file

@ -0,0 +1,30 @@
export type GetUserOrdersAllPairsResPair = {
id: number;
firstCurrency: {
id: number;
ticker: string;
};
secondCurrency: {
id: number;
ticker: string;
};
};
export type GetUserOrdersAllPairsSuccessRes = {
success: true;
data: GetUserOrdersAllPairsResPair[];
};
export enum GetUserOrdersAllPairsErrorCode {
// eslint-disable-next-line no-unused-vars
UNHANDLED_ERROR = 'Unhandled error',
}
export type GetUserOrdersAllPairsErrorRes = {
success: false;
data: GetUserOrdersAllPairsErrorCode;
};
type GetUserOrdersAllPairsRes = GetUserOrdersAllPairsSuccessRes | GetUserOrdersAllPairsErrorRes;
export default GetUserOrdersAllPairsRes;

View file

@ -0,0 +1,74 @@
export type GetUserOrdersResCurrency = {
id: number;
name: string;
code: string;
type: string;
asset_id: string;
auto_parsed: boolean;
asset_info?: {
asset_id: string;
logo: string;
price_url: string;
ticker: string;
full_name: string;
total_max_supply: string;
current_supply: string;
decimal_point: number;
meta_info: string;
};
whitelisted: boolean;
};
export type GetUserOrdersResOrderData = {
id: number;
type: string;
timestamp: number;
side: string;
price: string;
amount: string;
total: string;
pair_id: number;
user_id: number;
status: string;
left: string;
hasNotification: boolean;
pair: {
id: number;
first_currency_id: number;
second_currency_id: number;
rate?: number;
coefficient?: number;
high?: number;
low?: number;
volume: number;
featured: boolean;
first_currency: GetUserOrdersResCurrency;
second_currency: GetUserOrdersResCurrency;
};
first_currency: GetUserOrdersResCurrency;
second_currency: GetUserOrdersResCurrency;
isInstant: boolean;
};
export type GetUserOrdersSuccessRes = {
success: true;
totalItemsCount: number;
data: GetUserOrdersResOrderData[];
};
export enum GetUserOrdersErrorCode {
// eslint-disable-next-line no-unused-vars
UNHANDLED_ERROR = 'Unhandled error',
}
export type GetUserOrdersErrorRes = {
success: false;
data: GetUserOrdersErrorCode;
};
type GetUserOrdersRes = GetUserOrdersSuccessRes | GetUserOrdersErrorRes;
export default GetUserOrdersRes;

View file

@ -1,13 +1,12 @@
import { Op } from 'sequelize';
import { Op, Transaction as SequelizeTransaction, WhereOptions } from 'sequelize';
import Decimal from 'decimal.js';
import TransactionWithOrders from '@/interfaces/common/Transaction.js';
import Currency from '@/schemes/Currency.js';
import {
OrderWithAllTransactions,
OrderWithPair,
OrderWithPairAndCurrencies,
PairWithCurrencies,
PairWithIdAndCurrencies,
} from '@/interfaces/database/modifiedRequests.js';
import configModel from './Config.js';
import dexModel from './Dex.js';
import userModel from './User.js';
import exchangeModel from './ExchangeTransactions.js';
@ -22,10 +21,9 @@ import io from '../server.js';
import ApplyTip from '../interfaces/responses/orders/ApplyTip.js';
import CreateOrderBody from '../interfaces/bodies/orders/CreateOrderBody.js';
import GetUserOrdersPageBody from '../interfaces/bodies/orders/GetUserOrdersPageBody.js';
import GetUserOrdersBody from '../interfaces/bodies/orders/GetUserOrdersBody.js';
import CancelOrderBody from '../interfaces/bodies/orders/CancelOrderBody.js';
import ApplyOrderBody from '../interfaces/bodies/orders/ApplyOrderBody.js';
import Order from '../schemes/Order';
import Order, { OrderStatus, OrderType } from '../schemes/Order';
import User from '../schemes/User';
import Transaction from '../schemes/Transaction';
import Pair from '../schemes/Pair';
@ -387,17 +385,85 @@ class OrdersModel {
}
}
async getUserOrders(body: GetUserOrdersBody) {
async getUserOrders({
address,
offset,
limit,
filterInfo: { pairId, status, type, date },
}: {
address: string;
offset: number;
limit: number;
filterInfo: {
pairId?: number;
status?: 'active' | 'finished';
type?: 'buy' | 'sell';
date?: {
from: number;
to: number;
};
};
}): Promise<
| {
success: false;
data: 'Internal error';
}
| {
success: true;
totalItemsCount: number;
data: {
id: number;
type: string;
timestamp: number;
side: string;
price: string;
amount: string;
total: string;
pair_id: number;
user_id: number;
status: string;
left: string;
hasNotification: boolean;
pair: PairWithCurrencies;
first_currency: Currency;
second_currency: Currency;
isInstant: boolean;
}[];
}
> {
try {
const userRow = await userModel.getUserRow(body.userData.address);
const userRow = await userModel.getUserRow(address);
if (!userRow) throw new Error('Invalid address from token.');
const orders = (await Order.findAll({
where: {
const ordersSelectWhereClause: WhereOptions = {
user_id: userRow.id,
},
...(pairId !== undefined ? { pair_id: pairId } : {}),
...(status !== undefined
? {
status:
status === 'finished' ? OrderStatus.FINISHED : OrderStatus.ACTIVE,
}
: {}),
...(type !== undefined
? { type: type === 'buy' ? OrderType.BUY : OrderType.SELL }
: {}),
...(date !== undefined
? { timestamp: { [Op.between]: [date.from, date.to] } }
: {}),
};
const totalItemsCount = await Order.count({
where: ordersSelectWhereClause,
});
const ordersRows = (await Order.findAll({
where: ordersSelectWhereClause,
order: [['timestamp', 'DESC']],
limit,
offset,
include: [
{
model: Pair,
@ -407,14 +473,32 @@ class OrdersModel {
],
})) as OrderWithPairAndCurrencies[];
const result = orders.map((e) => ({
...e.toJSON(),
const result = ordersRows.map((e) => ({
id: e.id,
type: e.type,
timestamp: e.timestamp,
side: e.side,
price: e.price,
amount: e.amount,
total: e.total,
pair_id: e.pair_id,
user_id: e.user_id,
status: e.status,
left: e.left,
hasNotification: e.hasNotification,
pair: e.pair,
first_currency: e.pair.first_currency,
second_currency: e.pair.second_currency,
isInstant: dexModel.isBotActive(e.id),
}));
return { success: true, data: result };
return {
success: true,
totalItemsCount,
data: result,
};
} catch (err) {
console.log(err);
return { success: false, data: 'Internal error' };
@ -728,6 +812,184 @@ class OrdersModel {
return { success: false, data: 'Internal error' };
}
}
static GET_USER_ORDERS_ALL_PAIRS_USER_NOT_FOUND = 'No user found';
getUserOrdersAllPairs = async (
address: string,
): Promise<{
success: true;
data: {
id: number;
firstCurrency: {
id: number;
ticker: string;
};
secondCurrency: {
id: number;
ticker: string;
};
}[];
}> => {
const userRow = await userModel.getUserRow(address);
if (!userRow) {
throw new Error(OrdersModel.GET_USER_ORDERS_ALL_PAIRS_USER_NOT_FOUND);
}
// Select distinct pair IDs for the user's orders, then fetch pairs
const distinctPairIdRows = (await Order.findAll({
attributes: [[sequelize.fn('DISTINCT', sequelize.col('pair_id')), 'pair_id']],
where: { user_id: userRow.id },
raw: true,
})) as { pair_id: number }[];
const pairIds = distinctPairIdRows.map((row) => row.pair_id);
const pairsSelection = (await Pair.findAll({
where: { id: pairIds },
include: [
{ model: Currency, as: 'first_currency' },
{ model: Currency, as: 'second_currency' },
],
attributes: ['id'],
})) as PairWithIdAndCurrencies[];
const pairs = pairsSelection.map((e) => {
const firstCurrencyTicker = e.first_currency.name;
const secondCurrencyTicker = e.second_currency.name;
return {
id: e.id,
firstCurrency: {
id: e.first_currency.id,
ticker: firstCurrencyTicker,
},
secondCurrency: {
id: e.second_currency.id,
ticker: secondCurrencyTicker,
},
};
});
return {
success: true,
data: pairs,
};
};
static CANCEL_ALL_USER_NOT_FOUND = 'No user found';
cancelAll = async (
{
address,
filterInfo: { pairId, type, date },
}: {
address: string;
filterInfo: {
pairId?: number;
type?: 'buy' | 'sell';
date?: {
from: number;
to: number;
};
};
},
{ transaction }: { transaction: SequelizeTransaction },
): Promise<{
success: true;
}> => {
const userRow = await userModel.getUserRow(address);
if (!userRow) {
throw new Error(OrdersModel.CANCEL_ALL_USER_NOT_FOUND);
}
const ordersToCancelWhereClause: WhereOptions = {
user_id: userRow.id,
status: {
[Op.ne]: OrderStatus.FINISHED,
},
...(pairId !== undefined ? { pair_id: pairId } : {}),
...(type !== undefined
? { type: type === 'buy' ? OrderType.BUY : OrderType.SELL }
: {}),
...(date !== undefined ? { timestamp: { [Op.between]: [date.from, date.to] } } : {}),
};
const ORDERS_PER_CANCEL_CHUNK = 10_000;
let lastOrderTimestamp: number | undefined;
let finished = false;
while (!finished) {
const orderRows = await Order.findAll({
where: {
...ordersToCancelWhereClause,
...(lastOrderTimestamp !== undefined
? { timestamp: { [Op.gt]: lastOrderTimestamp } }
: {}),
},
order: [['timestamp', 'ASC']],
limit: ORDERS_PER_CANCEL_CHUNK,
});
const lastOrderRow = orderRows.at(-1);
// if there are no more orders to cancel, finish the process
if (!lastOrderRow) {
finished = true;
}
for (const orderRow of orderRows) {
await this.cancelOrderNotifications(orderRow, userRow);
const eps = new Decimal(1e-8);
const leftDecimal = new Decimal(orderRow.left);
const amountDecimal = new Decimal(orderRow.amount);
// if order was partially filled
if (leftDecimal.minus(amountDecimal).abs().greaterThan(eps)) {
const connectedTransactions = await Transaction.findAll({
where: {
[Op.or]: [
{ buy_order_id: orderRow.id },
{ sell_order_id: orderRow.id },
],
status: 'pending',
},
});
for (const tx of connectedTransactions) {
await exchangeModel.returnTransactionAmount(tx.id, transaction);
}
await Order.update(
{ status: OrderStatus.FINISHED },
{
where: { id: orderRow.id, user_id: userRow.id },
transaction,
},
);
} else {
await Order.destroy({
where: {
id: orderRow.id,
user_id: userRow.id,
},
transaction,
});
}
transaction.afterCommit(() => {
sendDeleteOrderMessage(io, orderRow.pair_id.toString(), orderRow.id.toString());
});
}
if (lastOrderRow) {
lastOrderTimestamp = lastOrderRow.timestamp;
}
}
return { success: true };
};
}
const ordersModel = new OrdersModel();

View file

@ -1,5 +1,9 @@
import express from 'express';
import { createOrderValidator } from '@/interfaces/bodies/orders/CreateOrderBody.js';
import { getUserOrdersValidator } from '@/interfaces/bodies/orders/GetUserOrdersBody.js';
import { getUserOrdersAllPairsValidator } from '@/interfaces/bodies/orders/GetUserOrdersAllPairsBody.js';
import { cancelAllValidator } from '@/interfaces/bodies/orders/CancelAllBody.js';
import middleware from '../middleware/middleware.js';
import ordersController from '../controllers/orders.controller.js';
@ -12,6 +16,8 @@ ordersRouter.use(
'/orders/get',
'/orders/cancel',
'/orders/apply-order',
'/orders/get-user-orders-pairs',
'/orders/cancel-all',
],
middleware.verifyToken,
);
@ -23,12 +29,26 @@ ordersRouter.post(
);
ordersRouter.post('/orders/get-page', ordersController.getOrdersPage);
ordersRouter.post('/orders/get-user-page', ordersController.getUserOrdersPage);
ordersRouter.post('/orders/get', ordersController.getUserOrders);
ordersRouter.patch(
'/orders/get',
middleware.expressValidator(getUserOrdersValidator),
ordersController.getUserOrders.bind(ordersController),
);
ordersRouter.post('/orders/cancel', ordersController.cancelOrder);
ordersRouter.post('/orders/get-candles', ordersController.getCandles);
ordersRouter.post('/orders/get-chart-orders', ordersController.getChartOrders);
ordersRouter.post('/orders/get-pair-stats', ordersController.getPairStats);
ordersRouter.post('/orders/apply-order', ordersController.applyOrder);
ordersRouter.post('/orders/get-trades', ordersController.getTrades);
ordersRouter.patch(
'/orders/get-user-orders-pairs',
middleware.expressValidator(getUserOrdersAllPairsValidator),
ordersController.getUserOrdersAllPairs.bind(ordersController),
);
ordersRouter.patch(
'/orders/cancel-all',
middleware.expressValidator(cancelAllValidator),
ordersController.cancelAll.bind(ordersController),
);
export default ordersRouter;

View file

@ -1,6 +1,22 @@
import { Model, DataTypes } from 'sequelize';
import sequelize from '../sequelize';
export enum OrderType {
// eslint-disable-next-line no-unused-vars
BUY = 'buy',
// eslint-disable-next-line no-unused-vars
SELL = 'sell',
}
export enum OrderStatus {
// eslint-disable-next-line no-unused-vars
ACTIVE = 'active',
// eslint-disable-next-line no-unused-vars
ZERO = 'zero',
// eslint-disable-next-line no-unused-vars
FINISHED = 'finished',
}
class Order extends Model {
declare readonly id: number;
@ -8,6 +24,7 @@ class Order extends Model {
declare timestamp: number;
// Currently not used
declare side: string;
declare price: string;