feat(trading): update validation and rules on take profit and stop loss (#5987)
This commit is contained in:
parent
be9a5a3437
commit
b89523efb2
@ -48,7 +48,7 @@ export const TxDetailsShared = ({
|
|||||||
}: TxDetailsSharedProps) => {
|
}: TxDetailsSharedProps) => {
|
||||||
const { data } = useExplorerEpochForBlockQuery({
|
const { data } = useExplorerEpochForBlockQuery({
|
||||||
errorPolicy: 'ignore',
|
errorPolicy: 'ignore',
|
||||||
variables: { block: txData?.block.toString() || '' },
|
variables: { block: txData?.block?.toString() || '' },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!txData) {
|
if (!txData) {
|
||||||
|
@ -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', () => {
|
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', () => {
|
it('renders recurring label if the tx has a recurring property', () => {
|
||||||
|
@ -21,6 +21,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=true
|
||||||
NX_ISOLATED_MARGIN=true
|
NX_ISOLATED_MARGIN=true
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
NX_METAMASK_SNAPS=true
|
NX_METAMASK_SNAPS=true
|
||||||
|
@ -21,6 +21,8 @@ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supp
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=false
|
NX_SUCCESSOR_MARKETS=false
|
||||||
NX_STOP_ORDERS=false
|
NX_STOP_ORDERS=false
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=false
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=true
|
||||||
NX_ISOLATED_MARGIN=true
|
NX_ISOLATED_MARGIN=true
|
||||||
# NX_ICEBERG_ORDERS
|
# NX_ICEBERG_ORDERS
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
|
@ -21,6 +21,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=false
|
||||||
NX_ISOLATED_MARGIN=false
|
NX_ISOLATED_MARGIN=false
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
NX_METAMASK_SNAPS=true
|
NX_METAMASK_SNAPS=true
|
||||||
|
@ -21,6 +21,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=true
|
||||||
NX_ISOLATED_MARGIN=true
|
NX_ISOLATED_MARGIN=true
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
|
@ -22,6 +22,7 @@ NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=true
|
||||||
NX_ISOLATED_MARGIN=true
|
NX_ISOLATED_MARGIN=true
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
NX_METAMASK_SNAPS=true
|
NX_METAMASK_SNAPS=true
|
||||||
|
@ -22,6 +22,7 @@ NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/m
|
|||||||
# Cosmic elevator flags
|
# Cosmic elevator flags
|
||||||
NX_SUCCESSOR_MARKETS=true
|
NX_SUCCESSOR_MARKETS=true
|
||||||
NX_STOP_ORDERS=true
|
NX_STOP_ORDERS=true
|
||||||
|
NX_TAKE_PROFIT_STOP_LOSS=true
|
||||||
NX_ISOLATED_MARGIN=true
|
NX_ISOLATED_MARGIN=true
|
||||||
NX_ICEBERG_ORDERS=true
|
NX_ICEBERG_ORDERS=true
|
||||||
# NX_PRODUCT_PERPETUALS
|
# NX_PRODUCT_PERPETUALS
|
||||||
|
@ -28,8 +28,8 @@ export const DealTicketPriceTakeProfitStopLoss = ({
|
|||||||
quoteName,
|
quoteName,
|
||||||
}: DealTicketPriceTakeProfitStopLossProps) => {
|
}: DealTicketPriceTakeProfitStopLossProps) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const validateAmount = useValidateAmount();
|
|
||||||
const priceStep = determinePriceStep(market);
|
const priceStep = determinePriceStep(market);
|
||||||
|
const validateAmount = useValidateAmount();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
@ -50,15 +50,6 @@ export const DealTicketPriceTakeProfitStopLoss = ({
|
|||||||
name="takeProfit"
|
name="takeProfit"
|
||||||
control={control}
|
control={control}
|
||||||
rules={{
|
rules={{
|
||||||
min: {
|
|
||||||
value: priceStep,
|
|
||||||
message: t(
|
|
||||||
'Take profit price cannot be lower than {{priceStep}}',
|
|
||||||
{
|
|
||||||
priceStep,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
},
|
|
||||||
validate: validateAmount(priceStep, 'takeProfit'),
|
validate: validateAmount(priceStep, 'takeProfit'),
|
||||||
}}
|
}}
|
||||||
render={({ field, fieldState }) => (
|
render={({ field, fieldState }) => (
|
||||||
@ -103,12 +94,6 @@ export const DealTicketPriceTakeProfitStopLoss = ({
|
|||||||
name="stopLoss"
|
name="stopLoss"
|
||||||
control={control}
|
control={control}
|
||||||
rules={{
|
rules={{
|
||||||
min: {
|
|
||||||
value: priceStep,
|
|
||||||
message: t('Price cannot be lower than {{priceStep}}', {
|
|
||||||
priceStep,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
validate: validateAmount(priceStep, 'stopLoss'),
|
validate: validateAmount(priceStep, 'stopLoss'),
|
||||||
}}
|
}}
|
||||||
render={({ field, fieldState }) => (
|
render={({ field, fieldState }) => (
|
||||||
|
@ -77,7 +77,7 @@ import { DealTicketSizeIceberg } from './deal-ticket-size-iceberg';
|
|||||||
import noop from 'lodash/noop';
|
import noop from 'lodash/noop';
|
||||||
import { isNonPersistentOrder } from '../../utils/time-in-force-persistence';
|
import { isNonPersistentOrder } from '../../utils/time-in-force-persistence';
|
||||||
import { KeyValue } from './key-value';
|
import { KeyValue } from './key-value';
|
||||||
import { DocsLinks } from '@vegaprotocol/environment';
|
import { DocsLinks, useFeatureFlags } from '@vegaprotocol/environment';
|
||||||
import { useT } from '../../use-t';
|
import { useT } from '../../use-t';
|
||||||
import { DealTicketPriceTakeProfitStopLoss } from './deal-ticket-price-tp-sl';
|
import { DealTicketPriceTakeProfitStopLoss } from './deal-ticket-price-tp-sl';
|
||||||
import uniqueId from 'lodash/uniqueId';
|
import uniqueId from 'lodash/uniqueId';
|
||||||
@ -381,6 +381,7 @@ export const DealTicket = ({
|
|||||||
const disablePostOnlyCheckbox = nonPersistentOrder;
|
const disablePostOnlyCheckbox = nonPersistentOrder;
|
||||||
const disableReduceOnlyCheckbox = !nonPersistentOrder;
|
const disableReduceOnlyCheckbox = !nonPersistentOrder;
|
||||||
const disableIcebergCheckbox = nonPersistentOrder;
|
const disableIcebergCheckbox = nonPersistentOrder;
|
||||||
|
const featureFlags = useFeatureFlags((state) => state.flags);
|
||||||
|
|
||||||
const onSubmit = useCallback(
|
const onSubmit = useCallback(
|
||||||
(formValues: OrderFormValues) => {
|
(formValues: OrderFormValues) => {
|
||||||
@ -388,7 +389,11 @@ export const DealTicket = ({
|
|||||||
if (lastSubmitTime.current && now - lastSubmitTime.current < 1000) {
|
if (lastSubmitTime.current && now - lastSubmitTime.current < 1000) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (formValues.tpSl) {
|
if (
|
||||||
|
featureFlags.TAKE_PROFIT_STOP_LOSS &&
|
||||||
|
formValues.tpSl &&
|
||||||
|
(formValues.takeProfit || formValues.stopLoss)
|
||||||
|
) {
|
||||||
const reference = `${pubKey}-${now}-${uniqueId()}`;
|
const reference = `${pubKey}-${now}-${uniqueId()}`;
|
||||||
const batchMarketInstructions = mapFormValuesToTakeProfitAndStopLoss(
|
const batchMarketInstructions = mapFormValuesToTakeProfitAndStopLoss(
|
||||||
formValues,
|
formValues,
|
||||||
@ -409,7 +414,7 @@ export const DealTicket = ({
|
|||||||
}
|
}
|
||||||
lastSubmitTime.current = now;
|
lastSubmitTime.current = now;
|
||||||
},
|
},
|
||||||
[market, pubKey, submit]
|
[featureFlags.TAKE_PROFIT_STOP_LOSS, market, pubKey, submit]
|
||||||
);
|
);
|
||||||
useController({
|
useController({
|
||||||
name: 'type',
|
name: 'type',
|
||||||
@ -726,6 +731,7 @@ export const DealTicket = ({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{featureFlags.TAKE_PROFIT_STOP_LOSS && (
|
||||||
<Controller
|
<Controller
|
||||||
name="tpSl"
|
name="tpSl"
|
||||||
control={control}
|
control={control}
|
||||||
@ -747,6 +753,7 @@ export const DealTicket = ({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{isLimitType && iceberg && (
|
{isLimitType && iceberg && (
|
||||||
<DealTicketSizeIceberg
|
<DealTicketSizeIceberg
|
||||||
@ -758,7 +765,7 @@ export const DealTicket = ({
|
|||||||
peakSize={peakSize}
|
peakSize={peakSize}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{tpSl && (
|
{featureFlags.TAKE_PROFIT_STOP_LOSS && tpSl && (
|
||||||
<DealTicketPriceTakeProfitStopLoss
|
<DealTicketPriceTakeProfitStopLoss
|
||||||
market={market}
|
market={market}
|
||||||
takeProfitError={errors.takeProfit?.message}
|
takeProfitError={errors.takeProfit?.message}
|
||||||
|
@ -390,6 +390,12 @@ export const compileFeatureFlags = (refresh = false): FeatureFlags => {
|
|||||||
STOP_ORDERS: TRUTHY.includes(
|
STOP_ORDERS: TRUTHY.includes(
|
||||||
windowOrDefault('NX_STOP_ORDERS', process.env['NX_STOP_ORDERS']) as string
|
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(
|
ISOLATED_MARGIN: TRUTHY.includes(
|
||||||
windowOrDefault(
|
windowOrDefault(
|
||||||
'NX_ISOLATED_MARGIN',
|
'NX_ISOLATED_MARGIN',
|
||||||
|
@ -21,6 +21,7 @@ export type CosmicElevatorFlags = Pick<
|
|||||||
FeatureFlags,
|
FeatureFlags,
|
||||||
| 'ICEBERG_ORDERS'
|
| 'ICEBERG_ORDERS'
|
||||||
| 'ISOLATED_MARGIN'
|
| 'ISOLATED_MARGIN'
|
||||||
|
| 'TAKE_PROFIT_STOP_LOSS'
|
||||||
| 'STOP_ORDERS'
|
| 'STOP_ORDERS'
|
||||||
| 'SUCCESSOR_MARKETS'
|
| 'SUCCESSOR_MARKETS'
|
||||||
| 'PRODUCT_PERPETUALS'
|
| 'PRODUCT_PERPETUALS'
|
||||||
|
@ -67,6 +67,7 @@ export const envSchema = z
|
|||||||
const COSMIC_ELEVATOR_FLAGS = {
|
const COSMIC_ELEVATOR_FLAGS = {
|
||||||
SUCCESSOR_MARKETS: z.optional(z.boolean()),
|
SUCCESSOR_MARKETS: z.optional(z.boolean()),
|
||||||
STOP_ORDERS: z.optional(z.boolean()),
|
STOP_ORDERS: z.optional(z.boolean()),
|
||||||
|
TAKE_PROFIT_STOP_LOSS: z.optional(z.boolean()),
|
||||||
ISOLATED_MARGIN: z.optional(z.boolean()),
|
ISOLATED_MARGIN: z.optional(z.boolean()),
|
||||||
ICEBERG_ORDERS: z.optional(z.boolean()),
|
ICEBERG_ORDERS: z.optional(z.boolean()),
|
||||||
PRODUCT_PERPETUALS: z.optional(z.boolean()),
|
PRODUCT_PERPETUALS: z.optional(z.boolean()),
|
||||||
|
@ -197,6 +197,7 @@ export const MarketVolumeInfoPanel = ({ market }: MarketInfoProps) => {
|
|||||||
marketId={market.id}
|
marketId={market.id}
|
||||||
positionDecimalPlaces={market.positionDecimalPlaces}
|
positionDecimalPlaces={market.positionDecimalPlaces}
|
||||||
marketDecimals={market.decimalPlaces}
|
marketDecimals={market.decimalPlaces}
|
||||||
|
quoteUnit={getQuoteName(market)}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
openInterest: dash(data?.openInterest),
|
openInterest: dash(data?.openInterest),
|
||||||
@ -788,7 +789,7 @@ export const PriceMonitoringBoundsInfoPanel = ({
|
|||||||
|
|
||||||
return (
|
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">
|
<p className="col-span-1">
|
||||||
{t('{{probability}} probability price bounds', {
|
{t('{{probability}} probability price bounds', {
|
||||||
probability: formatNumberPercentage(
|
probability: formatNumberPercentage(
|
||||||
|
@ -7,7 +7,7 @@ export const useValidateAmount = () => {
|
|||||||
return useCallback(
|
return useCallback(
|
||||||
(step: number | string, field: string) => {
|
(step: number | string, field: string) => {
|
||||||
return (value?: string) => {
|
return (value?: string) => {
|
||||||
const isValid = validateAgainstStep(step, value);
|
const isValid = value ? validateAgainstStep(step, value) : true;
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
if (new BigNumber(step).isEqualTo(1)) {
|
if (new BigNumber(step).isEqualTo(1)) {
|
||||||
return t('{{field}} must be whole numbers for this market', {
|
return t('{{field}} must be whole numbers for this market', {
|
||||||
@ -33,7 +33,7 @@ const isMultipleOf = (value: BigNumber, multipleOf: BigNumber) =>
|
|||||||
|
|
||||||
export const validateAgainstStep = (
|
export const validateAgainstStep = (
|
||||||
step: string | number,
|
step: string | number,
|
||||||
input?: string | number
|
input: string | number
|
||||||
) => {
|
) => {
|
||||||
const stepValue = new BigNumber(step);
|
const stepValue = new BigNumber(step);
|
||||||
if (stepValue.isNaN()) {
|
if (stepValue.isNaN()) {
|
||||||
@ -45,6 +45,6 @@ export const validateAgainstStep = (
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = new BigNumber(input || '');
|
const value = new BigNumber(input);
|
||||||
return isMultipleOf(value, stepValue);
|
return isMultipleOf(value, stepValue);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user