feat(trading): update validation and rules on take profit and stop loss (#5987)

This commit is contained in:
m.ray 2024-03-13 19:43:18 +02:00 committed by GitHub
parent be9a5a3437
commit b89523efb2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 56 additions and 48 deletions

View File

@ -48,7 +48,7 @@ export const TxDetailsShared = ({
}: TxDetailsSharedProps) => {
const { data } = useExplorerEpochForBlockQuery({
errorPolicy: 'ignore',
variables: { block: txData?.block.toString() || '' },
variables: { block: txData?.block?.toString() || '' },
});
if (!txData) {

View File

@ -21,7 +21,7 @@ describe('TX: Transfer: getLabelForTransfer', () => {
},
};
expect(getTypeLabelForTransfer(mock)).toEqual('Reward top up transfer');
expect(getTypeLabelForTransfer(mock)).toEqual('Reward transfer');
});
it('renders reward top up label if the TO party is network', () => {
@ -32,7 +32,7 @@ describe('TX: Transfer: getLabelForTransfer', () => {
},
};
expect(getTypeLabelForTransfer(mock)).toEqual('Reward top up transfer');
expect(getTypeLabelForTransfer(mock)).toEqual('Reward transfer');
});
it('renders recurring label if the tx has a recurring property', () => {

View File

@ -21,6 +21,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_STOP_ORDERS=true
NX_TAKE_PROFIT_STOP_LOSS=true
NX_ISOLATED_MARGIN=true
NX_ICEBERG_ORDERS=true
NX_METAMASK_SNAPS=true

View File

@ -21,6 +21,8 @@ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supp
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=false
NX_STOP_ORDERS=false
NX_TAKE_PROFIT_STOP_LOSS=false
NX_TAKE_PROFIT_STOP_LOSS=true
NX_ISOLATED_MARGIN=true
# NX_ICEBERG_ORDERS
# NX_PRODUCT_PERPETUALS

View File

@ -21,6 +21,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_STOP_ORDERS=true
NX_TAKE_PROFIT_STOP_LOSS=false
NX_ISOLATED_MARGIN=false
NX_ICEBERG_ORDERS=true
NX_METAMASK_SNAPS=true

View File

@ -21,6 +21,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_STOP_ORDERS=true
NX_TAKE_PROFIT_STOP_LOSS=true
NX_ISOLATED_MARGIN=true
NX_ICEBERG_ORDERS=true
# NX_PRODUCT_PERPETUALS

View File

@ -22,6 +22,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_STOP_ORDERS=true
NX_TAKE_PROFIT_STOP_LOSS=true
NX_ISOLATED_MARGIN=true
NX_ICEBERG_ORDERS=true
NX_METAMASK_SNAPS=true

View File

@ -22,6 +22,7 @@ NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/m
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_STOP_ORDERS=true
NX_TAKE_PROFIT_STOP_LOSS=true
NX_ISOLATED_MARGIN=true
NX_ICEBERG_ORDERS=true
# NX_PRODUCT_PERPETUALS

View File

@ -28,8 +28,8 @@ export const DealTicketPriceTakeProfitStopLoss = ({
quoteName,
}: DealTicketPriceTakeProfitStopLossProps) => {
const t = useT();
const validateAmount = useValidateAmount();
const priceStep = determinePriceStep(market);
const validateAmount = useValidateAmount();
return (
<div className="mb-2">
@ -50,15 +50,6 @@ export const DealTicketPriceTakeProfitStopLoss = ({
name="takeProfit"
control={control}
rules={{
min: {
value: priceStep,
message: t(
'Take profit price cannot be lower than {{priceStep}}',
{
priceStep,
}
),
},
validate: validateAmount(priceStep, 'takeProfit'),
}}
render={({ field, fieldState }) => (
@ -103,12 +94,6 @@ export const DealTicketPriceTakeProfitStopLoss = ({
name="stopLoss"
control={control}
rules={{
min: {
value: priceStep,
message: t('Price cannot be lower than {{priceStep}}', {
priceStep,
}),
},
validate: validateAmount(priceStep, 'stopLoss'),
}}
render={({ field, fieldState }) => (

View File

@ -77,7 +77,7 @@ import { DealTicketSizeIceberg } from './deal-ticket-size-iceberg';
import noop from 'lodash/noop';
import { isNonPersistentOrder } from '../../utils/time-in-force-persistence';
import { KeyValue } from './key-value';
import { DocsLinks } from '@vegaprotocol/environment';
import { DocsLinks, useFeatureFlags } from '@vegaprotocol/environment';
import { useT } from '../../use-t';
import { DealTicketPriceTakeProfitStopLoss } from './deal-ticket-price-tp-sl';
import uniqueId from 'lodash/uniqueId';
@ -381,6 +381,7 @@ export const DealTicket = ({
const disablePostOnlyCheckbox = nonPersistentOrder;
const disableReduceOnlyCheckbox = !nonPersistentOrder;
const disableIcebergCheckbox = nonPersistentOrder;
const featureFlags = useFeatureFlags((state) => state.flags);
const onSubmit = useCallback(
(formValues: OrderFormValues) => {
@ -388,7 +389,11 @@ export const DealTicket = ({
if (lastSubmitTime.current && now - lastSubmitTime.current < 1000) {
return;
}
if (formValues.tpSl) {
if (
featureFlags.TAKE_PROFIT_STOP_LOSS &&
formValues.tpSl &&
(formValues.takeProfit || formValues.stopLoss)
) {
const reference = `${pubKey}-${now}-${uniqueId()}`;
const batchMarketInstructions = mapFormValuesToTakeProfitAndStopLoss(
formValues,
@ -409,7 +414,7 @@ export const DealTicket = ({
}
lastSubmitTime.current = now;
},
[market, pubKey, submit]
[featureFlags.TAKE_PROFIT_STOP_LOSS, market, pubKey, submit]
);
useController({
name: 'type',
@ -726,27 +731,29 @@ export const DealTicket = ({
)}
/>
)}
<Controller
name="tpSl"
control={control}
render={({ field }) => (
<Tooltip
description={
<p>{t('TP_SL_TOOLTIP', 'Take profit / Stop loss')}</p>
}
>
<div>
<Checkbox
name="tpSl"
checked={field.value}
onCheckedChange={field.onChange}
disabled={false}
label={t('TP / SL')}
/>
</div>
</Tooltip>
)}
/>
{featureFlags.TAKE_PROFIT_STOP_LOSS && (
<Controller
name="tpSl"
control={control}
render={({ field }) => (
<Tooltip
description={
<p>{t('TP_SL_TOOLTIP', 'Take profit / Stop loss')}</p>
}
>
<div>
<Checkbox
name="tpSl"
checked={field.value}
onCheckedChange={field.onChange}
disabled={false}
label={t('TP / SL')}
/>
</div>
</Tooltip>
)}
/>
)}
</div>
{isLimitType && iceberg && (
<DealTicketSizeIceberg
@ -758,7 +765,7 @@ export const DealTicket = ({
peakSize={peakSize}
/>
)}
{tpSl && (
{featureFlags.TAKE_PROFIT_STOP_LOSS && tpSl && (
<DealTicketPriceTakeProfitStopLoss
market={market}
takeProfitError={errors.takeProfit?.message}

View File

@ -390,6 +390,12 @@ export const compileFeatureFlags = (refresh = false): FeatureFlags => {
STOP_ORDERS: TRUTHY.includes(
windowOrDefault('NX_STOP_ORDERS', process.env['NX_STOP_ORDERS']) as string
),
TAKE_PROFIT_STOP_LOSS: TRUTHY.includes(
windowOrDefault(
'NX_TAKE_PROFIT_STOP_LOSS',
process.env['NX_TAKE_PROFIT_STOP_LOSS']
) as string
),
ISOLATED_MARGIN: TRUTHY.includes(
windowOrDefault(
'NX_ISOLATED_MARGIN',

View File

@ -21,6 +21,7 @@ export type CosmicElevatorFlags = Pick<
FeatureFlags,
| 'ICEBERG_ORDERS'
| 'ISOLATED_MARGIN'
| 'TAKE_PROFIT_STOP_LOSS'
| 'STOP_ORDERS'
| 'SUCCESSOR_MARKETS'
| 'PRODUCT_PERPETUALS'

View File

@ -67,6 +67,7 @@ export const envSchema = z
const COSMIC_ELEVATOR_FLAGS = {
SUCCESSOR_MARKETS: z.optional(z.boolean()),
STOP_ORDERS: z.optional(z.boolean()),
TAKE_PROFIT_STOP_LOSS: z.optional(z.boolean()),
ISOLATED_MARGIN: z.optional(z.boolean()),
ICEBERG_ORDERS: z.optional(z.boolean()),
PRODUCT_PERPETUALS: z.optional(z.boolean()),

View File

@ -197,6 +197,7 @@ export const MarketVolumeInfoPanel = ({ market }: MarketInfoProps) => {
marketId={market.id}
positionDecimalPlaces={market.positionDecimalPlaces}
marketDecimals={market.decimalPlaces}
quoteUnit={getQuoteName(market)}
/>
),
openInterest: dash(data?.openInterest),
@ -788,7 +789,7 @@ export const PriceMonitoringBoundsInfoPanel = ({
return (
<>
<div className="mb-2 grid grid-cols-2 text-sm">
<div className="mb-2 grid grid-cols-2 text-xs">
<p className="col-span-1">
{t('{{probability}} probability price bounds', {
probability: formatNumberPercentage(

View File

@ -7,7 +7,7 @@ export const useValidateAmount = () => {
return useCallback(
(step: number | string, field: string) => {
return (value?: string) => {
const isValid = validateAgainstStep(step, value);
const isValid = value ? validateAgainstStep(step, value) : true;
if (!isValid) {
if (new BigNumber(step).isEqualTo(1)) {
return t('{{field}} must be whole numbers for this market', {
@ -33,7 +33,7 @@ const isMultipleOf = (value: BigNumber, multipleOf: BigNumber) =>
export const validateAgainstStep = (
step: string | number,
input?: string | number
input: string | number
) => {
const stepValue = new BigNumber(step);
if (stepValue.isNaN()) {
@ -45,6 +45,6 @@ export const validateAgainstStep = (
return true;
}
const value = new BigNumber(input || '');
const value = new BigNumber(input);
return isMultipleOf(value, stepValue);
};