mango-v4-ui/utils/tradeForm.ts

211 lines
5.0 KiB
TypeScript
Raw Normal View History

2023-11-04 05:24:17 -07:00
import mangoStore from '@store/mangoStore'
import { OrderbookL2, isMangoError } from 'types'
import { notify } from './notifications'
import * as sentry from '@sentry/nextjs'
import { Bank } from '@blockworks-foundation/mango-v4'
2022-09-25 19:02:58 -07:00
export const calculateLimitPriceForMarketOrder = (
orderBook: OrderbookL2,
2022-09-25 19:02:58 -07:00
size: number,
2023-07-21 11:47:53 -07:00
side: 'buy' | 'sell',
2022-09-25 19:02:58 -07:00
): number => {
const orders = side === 'buy' ? orderBook.asks : orderBook.bids
let acc = 0
let selectedOrder
2022-11-19 17:40:06 -08:00
const orderSize = size
2022-09-25 19:02:58 -07:00
for (const order of orders) {
acc += order[1]
if (acc >= orderSize) {
2022-09-25 19:02:58 -07:00
selectedOrder = order
break
}
}
if (!selectedOrder) {
2023-01-19 12:31:45 -08:00
throw new Error(
2023-07-21 11:47:53 -07:00
'Unable to place market order for this order size. Please retry.',
2023-01-19 12:31:45 -08:00
)
2022-09-25 19:02:58 -07:00
}
if (side === 'buy') {
return selectedOrder[0] * 1.05
} else {
return selectedOrder[0] * 0.95
}
}
2022-11-25 02:10:23 -08:00
2023-01-02 11:50:09 -08:00
export const calculateEstPriceForBaseSize = (
orderBook: OrderbookL2,
size: number,
2023-07-21 11:47:53 -07:00
side: 'buy' | 'sell',
2023-01-02 11:50:09 -08:00
): number => {
const orders = side === 'buy' ? orderBook.asks : orderBook.bids
let acc = 0
let selectedOrder
const orderSize = size
for (const order of orders) {
acc += order[1]
if (acc >= orderSize) {
selectedOrder = order
break
}
}
if (!selectedOrder) {
throw new Error('Unable to calculate market order. Please retry.')
}
if (side === 'buy') {
return selectedOrder[0]
} else {
return selectedOrder[0]
}
}
2022-11-25 02:10:23 -08:00
export const calculateSlippage = (
orderBook: OrderbookL2,
2022-11-25 02:10:23 -08:00
size: number,
side: 'buy' | 'sell',
2023-07-21 11:47:53 -07:00
markPrice: number,
2022-11-25 02:10:23 -08:00
): number => {
const bb = orderBook?.bids?.length > 0 && Number(orderBook.bids[0][0])
const ba = orderBook?.asks?.length > 0 && Number(orderBook.asks[0][0])
const referencePrice = bb && ba ? (bb + ba) / 2 : markPrice
2022-12-14 10:48:13 -08:00
if (Number(size)) {
2023-01-02 11:50:09 -08:00
const estimatedPrice = calculateEstPriceForBaseSize(
orderBook,
Number(size),
2023-07-21 11:47:53 -07:00
side,
)
2022-11-25 02:10:23 -08:00
2022-12-14 10:48:13 -08:00
const slippageAbs =
Number(size) > 0 ? Math.abs(estimatedPrice - referencePrice) : 0
2023-01-02 11:50:09 -08:00
2022-12-14 10:48:13 -08:00
const slippageRel = (slippageAbs / referencePrice) * 100
return slippageRel
}
return 0
2022-11-25 02:10:23 -08:00
}
2023-11-04 05:24:17 -07:00
export const handlePlaceTriggerOrder = async (
positionBank: Bank | undefined,
quoteBank: Bank | undefined,
amountIn: number,
triggerPrice: string,
orderType: TriggerOrderTypes,
isReducingShort: boolean,
flipPrices: boolean,
setSubmitting: (s: boolean) => void,
) => {
try {
const client = mangoStore.getState().client
const group = mangoStore.getState().group
const actions = mangoStore.getState().actions
const mangoAccount = mangoStore.getState().mangoAccount.current
// const inputBank = mangoStore.getState().swap.inputBank
// const outputBank = mangoStore.getState().swap.outputBank
if (!mangoAccount || !group || !positionBank || !quoteBank || !triggerPrice)
return
setSubmitting(true)
// const amountIn = amountInAsDecimal.toNumber()
const isReduceLong = !isReducingShort
try {
let tx
if (orderType === TriggerOrderTypes.STOP_LOSS) {
if (isReduceLong) {
tx = await client.tcsStopLossOnDeposit(
group,
mangoAccount,
positionBank,
quoteBank,
parseFloat(triggerPrice),
flipPrices,
amountIn,
null,
null,
)
} else {
tx = await client.tcsStopLossOnBorrow(
group,
mangoAccount,
quoteBank,
positionBank,
parseFloat(triggerPrice),
!flipPrices,
amountIn,
null,
true,
null,
)
}
}
if (orderType === TriggerOrderTypes.TAKE_PROFIT) {
if (isReduceLong) {
tx = await client.tcsTakeProfitOnDeposit(
group,
mangoAccount,
positionBank,
quoteBank,
parseFloat(triggerPrice),
flipPrices,
amountIn,
null,
null,
)
} else {
tx = await client.tcsTakeProfitOnBorrow(
group,
mangoAccount,
quoteBank,
positionBank,
parseFloat(triggerPrice),
!flipPrices,
amountIn,
null,
true,
null,
)
}
}
notify({
title: 'Transaction confirmed',
type: 'success',
txid: tx?.signature,
noSound: true,
})
actions.fetchGroup()
await actions.reloadMangoAccount(tx?.slot)
} catch (e) {
console.error('onSwap error: ', e)
sentry.captureException(e)
if (isMangoError(e)) {
notify({
title: 'Transaction failed',
description: e.message,
txid: e?.txid,
type: 'error',
})
}
}
} catch (e) {
console.error('Swap error:', e)
} finally {
setSubmitting(false)
}
}
export enum OrderTypes {
LIMIT = 'Limit',
MARKET = 'Market',
}
export enum TriggerOrderTypes {
STOP_LOSS = 'trade:stop-loss',
TAKE_PROFIT = 'trade:take-profit',
}