Update Order Lines for Advanced Order Types

Added ability to visualize advanced order types in the trading view chart.

Also fixed the calculateMarketPrice bug that was not setting advanced limit orders to the limit price.
This commit is contained in:
impossiblepairs 2021-10-16 11:49:57 -07:00
parent 3b5c84bcc4
commit 504613aa07
2 changed files with 124 additions and 72 deletions

View File

@ -16,6 +16,7 @@ import { PerpOrder, PerpMarket } from '@blockworks-foundation/mango-client'
import { notify } from '../../utils/notifications' import { notify } from '../../utils/notifications'
import { sleep, formatUsdValue } from '../../utils' import { sleep, formatUsdValue } from '../../utils'
import useInterval from '../../hooks/useInterval' import useInterval from '../../hooks/useInterval'
import { PerpTriggerOrder } from '../../@types/types'
// This is a basic example of how to create a TV widget // This is a basic example of how to create a TV widget
// You can add more feature such as storing charts in localStorage // You can add more feature such as storing charts in localStorage
@ -46,7 +47,7 @@ const TVChartContainer = () => {
const selectedMarketName = selectedMarketConfig.name const selectedMarketName = selectedMarketConfig.name
const openOrders = useOpenOrders() const openOrders = useOpenOrders()
const actions = useMangoStore((s) => s.actions) const actions = useMangoStore((s) => s.actions )
const connected = useMangoStore((s) => s.wallet.connected) const connected = useMangoStore((s) => s.wallet.connected)
const selectedMarginAccount = const selectedMarginAccount =
useMangoStore.getState().selectedMangoAccount.current useMangoStore.getState().selectedMangoAccount.current
@ -150,7 +151,7 @@ const TVChartContainer = () => {
const handleCancelOrder = async ( const handleCancelOrder = async (
order: Order | PerpOrder, order: Order | PerpOrder | PerpTriggerOrder,
market: Market | PerpMarket market: Market | PerpMarket
) => { ) => {
const wallet = useMangoStore.getState().wallet.current const wallet = useMangoStore.getState().wallet.current
@ -158,7 +159,7 @@ const TVChartContainer = () => {
useMangoStore.getState().selectedMangoGroup.current useMangoStore.getState().selectedMangoGroup.current
const selectedMangoAccount = const selectedMangoAccount =
useMangoStore.getState().selectedMangoAccount.current useMangoStore.getState().selectedMangoAccount.current
const mangoClient = useMangoStore.getState().connection.client
let txid let txid
try { try {
if (!selectedMangoGroup || !selectedMangoAccount) return if (!selectedMangoGroup || !selectedMangoAccount) return
@ -171,13 +172,23 @@ const TVChartContainer = () => {
order as Order order as Order
) )
} else if (market instanceof PerpMarket) { } else if (market instanceof PerpMarket) {
txid = await mangoClient.cancelPerpOrder( if (order.perpTrigger?.clientOrderId ) {
selectedMangoGroup, txid = await mangoClient.removeAdvancedOrder(
selectedMangoAccount, selectedMangoGroup,
wallet, selectedMangoAccount,
market, wallet,
order as PerpOrder (order as PerpTriggerOrder).orderId
) )
} else {
txid = await mangoClient.cancelPerpOrder(
selectedMangoGroup,
selectedMangoAccount,
wallet,
market,
order as PerpOrder,
false
)
}
} }
notify({ title: 'Successfully cancelled order', txid }) notify({ title: 'Successfully cancelled order', txid })
toggleOrderInProgress(false) toggleOrderInProgress(false)
@ -188,17 +199,16 @@ const TVChartContainer = () => {
txid: e.txid, txid: e.txid,
type: 'error', type: 'error',
}) })
return false console.log('error', `${e}`)
} finally { } finally {
sleep(500).then(() => { actions.reloadMangoAccount()
actions.fetchMangoAccounts() actions.reloadOrders()
actions.updateOpenOrders() toggleOrderInProgress(false)
toggleOrderInProgress(false) toggleMoveInProgress(false)
toggleMoveInProgress(false)
})
} }
} }
const handleModifyOrder = async ( const handleModifyOrder = async (
order: Order | PerpOrder, order: Order | PerpOrder,
market: Market | PerpMarket, market: Market | PerpMarket,
@ -265,8 +275,8 @@ const TVChartContainer = () => {
togglePriceReset(true) togglePriceReset(true)
} finally { } finally {
sleep(1000).then(() => { sleep(1000).then(() => {
actions.fetchMangoAccounts() actions.fetchAllMangoAccounts()
actions.updateOpenOrders() actions.reloadOrders()
toggleOrderInProgress(false) toggleOrderInProgress(false)
toggleMoveInProgress(false) toggleMoveInProgress(false)
}) })
@ -283,51 +293,64 @@ const TVChartContainer = () => {
toggleOrderInProgress(true) toggleOrderInProgress(true)
const currentOrderPrice = order.price const currentOrderPrice = order.price
const updatedOrderPrice = this.getPrice() const updatedOrderPrice = this.getPrice()
if ( if (!order.perpTrigger?.clientOrderId) {
(order.side === 'buy' && if (
updatedOrderPrice > 1.05 * selectedMarketPrice) || (order.side === 'buy' &&
(order.side === 'sell' && updatedOrderPrice > 1.05 * selectedMarketPrice) ||
updatedOrderPrice < 0.95 * selectedMarketPrice) (order.side === 'sell' &&
) { updatedOrderPrice < 0.95 * selectedMarketPrice)
) {
tvWidgetRef.current.showNoticeDialog({
title: 'Order Price Outside Range',
body:
`Your order price (${formatUsdValue(
updatedOrderPrice
)}) is greater than 5% ${
order.side == 'buy' ? 'above' : 'below'
} the current market price (${formatUsdValue(
selectedMarketPrice
)}). ` +
' indicating you might incur significant slippage. <p><p>Please use the trade input form if you wish to accept the potential slippage.',
callback: () => {
this.setPrice(currentOrderPrice)
toggleMoveInProgress(false)
toggleOrderInProgress(false)
},
})
} else {
tvWidgetRef.current.showConfirmDialog({
title: 'Modify Your Order?',
body: `Would you like to change your order from a
${order.size} ${market.config.baseSymbol} ${
order.side
} at $${currentOrderPrice}
to a
${order.size} ${market.config.baseSymbol} LIMIT ${
order.side
} at $${updatedOrderPrice}?
`,
callback: (res) => {
if (res) {
handleModifyOrder(order, market.account, updatedOrderPrice)
} else {
this.setPrice(currentOrderPrice)
toggleOrderInProgress(false)
toggleMoveInProgress(false)
}
},
})
}
} else {
tvWidgetRef.current.showNoticeDialog({ tvWidgetRef.current.showNoticeDialog({
title: 'Order Price Outside Range', title: 'Advanced Order Type',
body: body:
`Your order price (${formatUsdValue( 'Advanced order types in the chart window may only be cancelled. If new conditions are required, please cancel this order and use the Advanced Trade Form.',
updatedOrderPrice
)}) is greater than 5% ${
order.side == 'buy' ? 'above' : 'below'
} the current market price (${formatUsdValue(
selectedMarketPrice
)}). ` +
' indicating you might incur significant slippage. <p><p>Please use the trade input form if you wish to accept the potential slippage.',
callback: () => { callback: () => {
this.setPrice(currentOrderPrice) this.setPrice(currentOrderPrice)
toggleMoveInProgress(false) toggleMoveInProgress(false)
toggleOrderInProgress(false) toggleOrderInProgress(false)
}, },
}) })
} else {
tvWidgetRef.current.showConfirmDialog({
title: 'Modify Your Order?',
body: `Would you like to change your order from a
${order.size} ${market.config.baseSymbol} ${
order.side
} at ${formatUsdValue(currentOrderPrice)}
to a
${order.size} ${market.config.baseSymbol} LIMIT ${
order.side
} at ${formatUsdValue(updatedOrderPrice)}?
`,
callback: (res) => {
if (res) {
handleModifyOrder(order, market.account, updatedOrderPrice)
} else {
this.setPrice(currentOrderPrice)
toggleOrderInProgress(false)
toggleMoveInProgress(false)
}
},
})
} }
}) })
.onCancel(function () { .onCancel(function () {
@ -337,7 +360,7 @@ const TVChartContainer = () => {
body: `Would you like to cancel your order for body: `Would you like to cancel your order for
${order.size} ${market.config.baseSymbol} ${ ${order.size} ${market.config.baseSymbol} ${
order.side order.side
} at ${formatUsdValue(order.price)} } at $${order.price}
`, `,
callback: (res) => { callback: (res) => {
if (res) { if (res) {
@ -348,21 +371,46 @@ const TVChartContainer = () => {
}, },
}) })
}) })
.setText(`${order.side.toUpperCase()} ${market.config.baseSymbol}`)
.setBodyBorderColor(order.side == 'buy' ? '#AFD803' : '#E54033')
.setBodyBackgroundColor('#000000')
.setBodyTextColor('#F2C94C')
.setLineLength(3)
.setLineColor(order.side == 'buy' ? '#AFD803' : '#E54033')
.setQuantity(order.size)
.setTooltip(`Order #: ${order.orderId}`)
.setQuantityBorderColor(order.side == 'buy' ? '#AFD803' : '#E54033')
.setQuantityBackgroundColor('#000000')
.setQuantityTextColor('#F2C94C')
.setCancelButtonBorderColor(order.side == 'buy' ? '#AFD803' : '#E54033')
.setCancelButtonBackgroundColor('#000000')
.setCancelButtonIconColor('#F2C94C')
.setPrice(order.price) .setPrice(order.price)
.setQuantity(order.size)
.setText(getLineText(order, market))
.setTooltip(order.perpTrigger?.clientOrderId ? `${order.orderType} Order #: ${order.orderId}` : `Order #: ${order.orderId}`)
.setBodyTextColor(theme === 'Dark' ? '#F2C94C' : theme === 'Light' ? '#FF9C24' : '#F2C94C')
.setQuantityTextColor(theme === 'Dark' ? '#F2C94C' : theme === 'Light' ? '#FF9C24' : '#F2C94C')
.setCancelButtonIconColor(theme === 'Dark' ? '#F2C94C' : theme === 'Light' ? '#FF9C24' : '#F2C94C')
.setBodyBorderColor(order.perpTrigger?.clientOrderId ? '#FF9C24' : order.side == 'buy' ? '#4BA53B' : '#AA2222')
.setQuantityBorderColor(order.perpTrigger?.clientOrderId ? '#FF9C24' : order.side == 'buy' ? '#4BA53B' : '#AA2222')
.setCancelButtonBorderColor(order.perpTrigger?.clientOrderId ? '#FF9C24' : order.side == 'buy' ? '#4BA53B' : '#AA2222')
.setBodyBackgroundColor(theme === 'Dark' ? '#1B1B1F' : theme === 'Light' ? '#fff' : '#1D1832')
.setQuantityBackgroundColor(theme === 'Dark' ? '#1B1B1F' : theme === 'Light' ? '#fff' : '#1D1832')
.setCancelButtonBackgroundColor(theme === 'Dark' ? '#1B1B1F' : theme === 'Light' ? '#fff' : '#1D1832')
.setBodyFont('Lato, sans-serif')
.setQuantityFont('Lato, sans-serif')
.setLineColor(order.perpTrigger?.clientOrderId ? '#FF9C24' : order.side == 'buy' ? '#4BA53B' : '#AA2222')
.setLineLength(3)
.setLineWidth(2)
.setLineStyle(1)
}
function getLineText(order, market) {
if (order.perpTrigger?.clientOrderId) {
if (order.side === 'buy') {
if (order.perpTrigger.triggerCondition === 'above') {
return (order.orderType === 'market' ? `Stop Loss ` : `Stop Limit `) + `(${order.orderType} ${order.side}) if price is ${order.perpTrigger.triggerCondition} $${Number(order.perpTrigger.triggerPrice)}`
} else {
return `Take Profit (${order.orderType} ${order.side}) if price is ${order.perpTrigger.triggerCondition} $${Number(order.perpTrigger.triggerPrice)}`
}
} else {
if (order.perpTrigger.triggerCondition === 'below') {
return (order.orderType === 'market' ? `Stop Loss ` : `Stop Limit `) + `(${order.orderType} ${order.side}) if price is ${order.perpTrigger.triggerCondition} $${Number(order.perpTrigger.triggerPrice)}`
} else {
return `Take Profit (${order.orderType} ${order.side}) if price is ${order.perpTrigger.triggerCondition} $${Number(order.perpTrigger.triggerPrice)}`
}
}
} else {
return `${order.side} ${market.config.baseSymbol}`.toUpperCase()
}
} }

View File

@ -108,7 +108,11 @@ export function calculateTradePrice(
if (tradeType === 'Market') { if (tradeType === 'Market') {
return calculateMarketPrice(orderBook, baseSize, side) return calculateMarketPrice(orderBook, baseSize, side)
} else if (TRIGGER_ORDER_TYPES.includes(tradeType)) { } else if (TRIGGER_ORDER_TYPES.includes(tradeType)) {
return Number(triggerPrice) if( tradeType === 'Take Profit Limit' || tradeType === 'Stop Limit' ) {
return Number(price)
} else {
return Number(triggerPrice)
}
} }
return Number(price) return Number(price)
} }