@drift-labs/sdk 2.12.0-beta.3 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/dlob/DLOB.d.ts +8 -8
- package/lib/dlob/DLOB.js +24 -17
- package/lib/idl/drift.json +1 -1
- package/lib/math/trade.d.ts +35 -3
- package/lib/math/trade.js +192 -14
- package/package.json +1 -1
- package/src/dlob/DLOB.ts +34 -26
- package/src/idl/drift.json +1 -1
- package/src/math/trade.ts +322 -16
- package/tests/dlob/test.ts +307 -38
package/src/math/trade.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
MarketType,
|
|
3
|
+
PerpMarketAccount,
|
|
4
|
+
PositionDirection,
|
|
5
|
+
SpotMarketAccount,
|
|
6
|
+
} from '../types';
|
|
2
7
|
import { BN } from '@project-serum/anchor';
|
|
3
8
|
import { assert } from '../assert/assert';
|
|
4
9
|
import {
|
|
@@ -7,6 +12,7 @@ import {
|
|
|
7
12
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
8
13
|
ZERO,
|
|
9
14
|
BASE_PRECISION,
|
|
15
|
+
BN_MAX,
|
|
10
16
|
} from '../constants/numericConstants';
|
|
11
17
|
import {
|
|
12
18
|
calculateBidPrice,
|
|
@@ -20,11 +26,14 @@ import {
|
|
|
20
26
|
AssetType,
|
|
21
27
|
calculateUpdatedAMMSpreadReserves,
|
|
22
28
|
calculateQuoteAssetAmountSwapped,
|
|
29
|
+
calculateMarketOpenBidAsk,
|
|
23
30
|
} from './amm';
|
|
24
31
|
import { squareRootBN } from './utils';
|
|
25
32
|
import { isVariant } from '../types';
|
|
26
33
|
import { OraclePriceData } from '../oracles/types';
|
|
27
34
|
import { DLOB } from '../dlob/DLOB';
|
|
35
|
+
import { PublicKey } from '@solana/web3.js';
|
|
36
|
+
import { Orderbook } from '@project-serum/serum';
|
|
28
37
|
|
|
29
38
|
const MAXPCT = new BN(1000); //percentage units are [0,1000] => [0,1]
|
|
30
39
|
|
|
@@ -363,7 +372,7 @@ export function calculateTargetPriceTrade(
|
|
|
363
372
|
* @param oraclePriceData
|
|
364
373
|
* @param dlob
|
|
365
374
|
* @param slot
|
|
366
|
-
* @param
|
|
375
|
+
* @param usersToSkip
|
|
367
376
|
*/
|
|
368
377
|
export function calculateEstimatedPerpEntryPrice(
|
|
369
378
|
assetType: AssetType,
|
|
@@ -373,21 +382,37 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
373
382
|
oraclePriceData: OraclePriceData,
|
|
374
383
|
dlob: DLOB,
|
|
375
384
|
slot: number,
|
|
376
|
-
|
|
377
|
-
):
|
|
385
|
+
usersToSkip = new Map<PublicKey, boolean>()
|
|
386
|
+
): {
|
|
387
|
+
entryPrice: BN;
|
|
388
|
+
priceImpact: BN;
|
|
389
|
+
bestPrice: BN;
|
|
390
|
+
worstPrice: BN;
|
|
391
|
+
baseFilled: BN;
|
|
392
|
+
quoteFilled: BN;
|
|
393
|
+
} {
|
|
378
394
|
if (amount.eq(ZERO)) {
|
|
379
|
-
return
|
|
395
|
+
return {
|
|
396
|
+
entryPrice: ZERO,
|
|
397
|
+
priceImpact: ZERO,
|
|
398
|
+
bestPrice: ZERO,
|
|
399
|
+
worstPrice: ZERO,
|
|
400
|
+
baseFilled: ZERO,
|
|
401
|
+
quoteFilled: ZERO,
|
|
402
|
+
};
|
|
380
403
|
}
|
|
381
404
|
|
|
382
405
|
const takerIsLong = isVariant(direction, 'long');
|
|
383
406
|
const limitOrders = dlob[
|
|
384
|
-
takerIsLong ? '
|
|
407
|
+
takerIsLong ? 'getMakerLimitAsks' : 'getMakerLimitBids'
|
|
385
408
|
](
|
|
386
409
|
market.marketIndex,
|
|
387
410
|
slot,
|
|
388
411
|
MarketType.PERP,
|
|
389
412
|
oraclePriceData,
|
|
390
|
-
|
|
413
|
+
takerIsLong
|
|
414
|
+
? calculateBidPrice(market, oraclePriceData)
|
|
415
|
+
: calculateAskPrice(market, oraclePriceData)
|
|
391
416
|
);
|
|
392
417
|
|
|
393
418
|
const swapDirection = getSwapDirection(assetType, direction);
|
|
@@ -401,9 +426,34 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
401
426
|
pegMultiplier: newPeg,
|
|
402
427
|
};
|
|
403
428
|
|
|
429
|
+
const [ammBids, ammAsks] = calculateMarketOpenBidAsk(
|
|
430
|
+
market.amm.baseAssetReserve,
|
|
431
|
+
market.amm.minBaseAssetReserve,
|
|
432
|
+
market.amm.maxBaseAssetReserve,
|
|
433
|
+
market.amm.orderStepSize
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
let ammLiquidity: BN;
|
|
437
|
+
if (assetType === 'base') {
|
|
438
|
+
ammLiquidity = takerIsLong ? ammAsks.abs() : ammBids;
|
|
439
|
+
} else {
|
|
440
|
+
const [afterSwapQuoteReserves, _] = calculateAmmReservesAfterSwap(
|
|
441
|
+
amm,
|
|
442
|
+
'base',
|
|
443
|
+
takerIsLong ? ammAsks.abs() : ammBids,
|
|
444
|
+
getSwapDirection('base', direction)
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
ammLiquidity = calculateQuoteAssetAmountSwapped(
|
|
448
|
+
amm.quoteAssetReserve.sub(afterSwapQuoteReserves).abs(),
|
|
449
|
+
amm.pegMultiplier,
|
|
450
|
+
swapDirection
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
404
454
|
const invariant = amm.sqrtK.mul(amm.sqrtK);
|
|
405
455
|
|
|
406
|
-
let
|
|
456
|
+
let bestPrice = calculatePrice(
|
|
407
457
|
amm.baseAssetReserve,
|
|
408
458
|
amm.quoteAssetReserve,
|
|
409
459
|
amm.pegMultiplier
|
|
@@ -415,13 +465,18 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
415
465
|
let limitOrder = limitOrders.next().value;
|
|
416
466
|
if (limitOrder) {
|
|
417
467
|
const limitOrderPrice = limitOrder.getPrice(oraclePriceData, slot);
|
|
418
|
-
|
|
419
|
-
? BN.min(limitOrderPrice,
|
|
420
|
-
: BN.max(limitOrderPrice,
|
|
468
|
+
bestPrice = takerIsLong
|
|
469
|
+
? BN.min(limitOrderPrice, bestPrice)
|
|
470
|
+
: BN.max(limitOrderPrice, bestPrice);
|
|
421
471
|
}
|
|
422
472
|
|
|
473
|
+
let worstPrice = bestPrice;
|
|
474
|
+
|
|
423
475
|
if (assetType === 'base') {
|
|
424
|
-
while (
|
|
476
|
+
while (
|
|
477
|
+
!cumulativeBaseFilled.eq(amount) &&
|
|
478
|
+
(ammLiquidity.gt(ZERO) || limitOrder)
|
|
479
|
+
) {
|
|
425
480
|
const limitOrderPrice = limitOrder?.getPrice(oraclePriceData, slot);
|
|
426
481
|
|
|
427
482
|
let maxAmmFill: BN;
|
|
@@ -442,11 +497,15 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
442
497
|
maxAmmFill = amount.sub(cumulativeBaseFilled);
|
|
443
498
|
}
|
|
444
499
|
|
|
500
|
+
maxAmmFill = BN.min(maxAmmFill, ammLiquidity);
|
|
501
|
+
|
|
445
502
|
if (maxAmmFill.gt(ZERO)) {
|
|
446
503
|
const baseFilled = BN.min(amount.sub(cumulativeBaseFilled), maxAmmFill);
|
|
447
504
|
const [afterSwapQuoteReserves, afterSwapBaseReserves] =
|
|
448
505
|
calculateAmmReservesAfterSwap(amm, 'base', baseFilled, swapDirection);
|
|
449
506
|
|
|
507
|
+
ammLiquidity = ammLiquidity.sub(baseFilled);
|
|
508
|
+
|
|
450
509
|
const quoteFilled = calculateQuoteAssetAmountSwapped(
|
|
451
510
|
amm.quoteAssetReserve.sub(afterSwapQuoteReserves).abs(),
|
|
452
511
|
amm.pegMultiplier,
|
|
@@ -459,11 +518,21 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
459
518
|
amm.baseAssetReserve = afterSwapBaseReserves;
|
|
460
519
|
amm.quoteAssetReserve = afterSwapQuoteReserves;
|
|
461
520
|
|
|
521
|
+
worstPrice = calculatePrice(
|
|
522
|
+
amm.baseAssetReserve,
|
|
523
|
+
amm.quoteAssetReserve,
|
|
524
|
+
amm.pegMultiplier
|
|
525
|
+
);
|
|
526
|
+
|
|
462
527
|
if (cumulativeBaseFilled.eq(amount)) {
|
|
463
528
|
break;
|
|
464
529
|
}
|
|
465
530
|
}
|
|
466
531
|
|
|
532
|
+
if (limitOrder && usersToSkip.has(limitOrder.userAccount)) {
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
|
|
467
536
|
const baseFilled = BN.min(
|
|
468
537
|
limitOrder.order.baseAssetAmount.sub(
|
|
469
538
|
limitOrder.order.baseAssetAmountFilled
|
|
@@ -475,6 +544,8 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
475
544
|
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
476
545
|
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
477
546
|
|
|
547
|
+
worstPrice = limitOrderPrice;
|
|
548
|
+
|
|
478
549
|
if (cumulativeBaseFilled.eq(amount)) {
|
|
479
550
|
break;
|
|
480
551
|
}
|
|
@@ -482,7 +553,10 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
482
553
|
limitOrder = limitOrders.next().value;
|
|
483
554
|
}
|
|
484
555
|
} else {
|
|
485
|
-
while (
|
|
556
|
+
while (
|
|
557
|
+
!cumulativeQuoteFilled.eq(amount) &&
|
|
558
|
+
(ammLiquidity.gt(ZERO) || limitOrder)
|
|
559
|
+
) {
|
|
486
560
|
const limitOrderPrice = limitOrder?.getPrice(oraclePriceData, slot);
|
|
487
561
|
|
|
488
562
|
let maxAmmFill: BN;
|
|
@@ -503,6 +577,8 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
503
577
|
maxAmmFill = amount.sub(cumulativeQuoteFilled);
|
|
504
578
|
}
|
|
505
579
|
|
|
580
|
+
maxAmmFill = BN.min(maxAmmFill, ammLiquidity);
|
|
581
|
+
|
|
506
582
|
if (maxAmmFill.gt(ZERO)) {
|
|
507
583
|
const quoteFilled = BN.min(
|
|
508
584
|
amount.sub(cumulativeQuoteFilled),
|
|
@@ -516,6 +592,8 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
516
592
|
swapDirection
|
|
517
593
|
);
|
|
518
594
|
|
|
595
|
+
ammLiquidity = ammLiquidity.sub(quoteFilled);
|
|
596
|
+
|
|
519
597
|
const baseFilled = afterSwapBaseReserves
|
|
520
598
|
.sub(amm.baseAssetReserve)
|
|
521
599
|
.abs();
|
|
@@ -526,11 +604,21 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
526
604
|
amm.baseAssetReserve = afterSwapBaseReserves;
|
|
527
605
|
amm.quoteAssetReserve = afterSwapQuoteReserves;
|
|
528
606
|
|
|
607
|
+
worstPrice = calculatePrice(
|
|
608
|
+
amm.baseAssetReserve,
|
|
609
|
+
amm.quoteAssetReserve,
|
|
610
|
+
amm.pegMultiplier
|
|
611
|
+
);
|
|
612
|
+
|
|
529
613
|
if (cumulativeQuoteFilled.eq(amount)) {
|
|
530
614
|
break;
|
|
531
615
|
}
|
|
532
616
|
}
|
|
533
617
|
|
|
618
|
+
if (limitOrder && usersToSkip.has(limitOrder.userAccount)) {
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
|
|
534
622
|
const quoteFilled = BN.min(
|
|
535
623
|
limitOrder.order.baseAssetAmount
|
|
536
624
|
.sub(limitOrder.order.baseAssetAmountFilled)
|
|
@@ -544,6 +632,8 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
544
632
|
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
545
633
|
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
546
634
|
|
|
635
|
+
worstPrice = limitOrderPrice;
|
|
636
|
+
|
|
547
637
|
if (cumulativeQuoteFilled.eq(amount)) {
|
|
548
638
|
break;
|
|
549
639
|
}
|
|
@@ -557,10 +647,226 @@ export function calculateEstimatedPerpEntryPrice(
|
|
|
557
647
|
.div(cumulativeBaseFilled);
|
|
558
648
|
|
|
559
649
|
const priceImpact = entryPrice
|
|
560
|
-
.sub(
|
|
650
|
+
.sub(bestPrice)
|
|
651
|
+
.mul(PRICE_PRECISION)
|
|
652
|
+
.div(bestPrice)
|
|
653
|
+
.abs();
|
|
654
|
+
|
|
655
|
+
return {
|
|
656
|
+
entryPrice,
|
|
657
|
+
priceImpact,
|
|
658
|
+
bestPrice,
|
|
659
|
+
worstPrice,
|
|
660
|
+
baseFilled: cumulativeBaseFilled,
|
|
661
|
+
quoteFilled: cumulativeQuoteFilled,
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Calculates the estimated entry price and price impact of order, in base or quote
|
|
667
|
+
* Price impact is based on the difference between the entry price and the best bid/ask price (whether it's dlob or serum)
|
|
668
|
+
*
|
|
669
|
+
* @param assetType
|
|
670
|
+
* @param amount
|
|
671
|
+
* @param direction
|
|
672
|
+
* @param market
|
|
673
|
+
* @param oraclePriceData
|
|
674
|
+
* @param dlob
|
|
675
|
+
* @param serumBids
|
|
676
|
+
* @param serumAsks
|
|
677
|
+
* @param slot
|
|
678
|
+
* @param usersToSkip
|
|
679
|
+
*/
|
|
680
|
+
export function calculateEstimatedSpotEntryPrice(
|
|
681
|
+
assetType: AssetType,
|
|
682
|
+
amount: BN,
|
|
683
|
+
direction: PositionDirection,
|
|
684
|
+
market: SpotMarketAccount,
|
|
685
|
+
oraclePriceData: OraclePriceData,
|
|
686
|
+
dlob: DLOB,
|
|
687
|
+
serumBids: Orderbook,
|
|
688
|
+
serumAsks: Orderbook,
|
|
689
|
+
slot: number,
|
|
690
|
+
usersToSkip = new Map<PublicKey, boolean>()
|
|
691
|
+
): {
|
|
692
|
+
entryPrice: BN;
|
|
693
|
+
priceImpact: BN;
|
|
694
|
+
bestPrice: BN;
|
|
695
|
+
worstPrice: BN;
|
|
696
|
+
baseFilled: BN;
|
|
697
|
+
quoteFilled: BN;
|
|
698
|
+
} {
|
|
699
|
+
if (amount.eq(ZERO)) {
|
|
700
|
+
return {
|
|
701
|
+
entryPrice: ZERO,
|
|
702
|
+
priceImpact: ZERO,
|
|
703
|
+
bestPrice: ZERO,
|
|
704
|
+
worstPrice: ZERO,
|
|
705
|
+
baseFilled: ZERO,
|
|
706
|
+
quoteFilled: ZERO,
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
const basePrecision = new BN(Math.pow(10, market.decimals));
|
|
711
|
+
|
|
712
|
+
const takerIsLong = isVariant(direction, 'long');
|
|
713
|
+
const dlobLimitOrders = dlob[
|
|
714
|
+
takerIsLong ? 'getMakerLimitAsks' : 'getMakerLimitBids'
|
|
715
|
+
](market.marketIndex, slot, MarketType.SPOT, oraclePriceData);
|
|
716
|
+
const serumLimitOrders = takerIsLong
|
|
717
|
+
? serumAsks.getL2(100)
|
|
718
|
+
: serumBids.getL2(100);
|
|
719
|
+
|
|
720
|
+
let cumulativeBaseFilled = ZERO;
|
|
721
|
+
let cumulativeQuoteFilled = ZERO;
|
|
722
|
+
|
|
723
|
+
let dlobLimitOrder = dlobLimitOrders.next().value;
|
|
724
|
+
let serumLimitOrder = serumLimitOrders.shift();
|
|
725
|
+
|
|
726
|
+
const dlobLimitOrderPrice = dlobLimitOrder?.getPrice(oraclePriceData, slot);
|
|
727
|
+
const serumLimitOrderPrice = serumLimitOrder
|
|
728
|
+
? new BN(serumLimitOrder[0] * PRICE_PRECISION.toNumber())
|
|
729
|
+
: undefined;
|
|
730
|
+
|
|
731
|
+
const bestPrice = takerIsLong
|
|
732
|
+
? BN.min(serumLimitOrderPrice || BN_MAX, dlobLimitOrderPrice || BN_MAX)
|
|
733
|
+
: BN.max(serumLimitOrderPrice || ZERO, dlobLimitOrderPrice || ZERO);
|
|
734
|
+
let worstPrice = bestPrice;
|
|
735
|
+
|
|
736
|
+
if (assetType === 'base') {
|
|
737
|
+
while (
|
|
738
|
+
!cumulativeBaseFilled.eq(amount) &&
|
|
739
|
+
(dlobLimitOrder || serumLimitOrder)
|
|
740
|
+
) {
|
|
741
|
+
const dlobLimitOrderPrice = dlobLimitOrder?.getPrice(
|
|
742
|
+
oraclePriceData,
|
|
743
|
+
slot
|
|
744
|
+
);
|
|
745
|
+
const serumLimitOrderPrice = serumLimitOrder
|
|
746
|
+
? new BN(serumLimitOrder[0] * PRICE_PRECISION.toNumber())
|
|
747
|
+
: undefined;
|
|
748
|
+
|
|
749
|
+
const useSerum = takerIsLong
|
|
750
|
+
? (serumLimitOrderPrice || BN_MAX).lt(dlobLimitOrderPrice || BN_MAX)
|
|
751
|
+
: (serumLimitOrderPrice || ZERO).gt(dlobLimitOrderPrice || ZERO);
|
|
752
|
+
|
|
753
|
+
if (!useSerum) {
|
|
754
|
+
if (dlobLimitOrder && usersToSkip.has(dlobLimitOrder.userAccount)) {
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const baseFilled = BN.min(
|
|
759
|
+
dlobLimitOrder.order.baseAssetAmount.sub(
|
|
760
|
+
dlobLimitOrder.order.baseAssetAmountFilled
|
|
761
|
+
),
|
|
762
|
+
amount.sub(cumulativeBaseFilled)
|
|
763
|
+
);
|
|
764
|
+
const quoteFilled = baseFilled
|
|
765
|
+
.mul(dlobLimitOrderPrice)
|
|
766
|
+
.div(basePrecision);
|
|
767
|
+
|
|
768
|
+
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
769
|
+
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
770
|
+
|
|
771
|
+
worstPrice = dlobLimitOrder;
|
|
772
|
+
|
|
773
|
+
dlobLimitOrder = dlobLimitOrders.next().value;
|
|
774
|
+
} else {
|
|
775
|
+
const baseFilled = BN.min(
|
|
776
|
+
new BN(serumLimitOrder[1] * basePrecision.toNumber()),
|
|
777
|
+
amount.sub(cumulativeBaseFilled)
|
|
778
|
+
);
|
|
779
|
+
const quoteFilled = baseFilled
|
|
780
|
+
.mul(serumLimitOrderPrice)
|
|
781
|
+
.div(basePrecision);
|
|
782
|
+
|
|
783
|
+
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
784
|
+
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
785
|
+
|
|
786
|
+
worstPrice = serumLimitOrderPrice;
|
|
787
|
+
|
|
788
|
+
serumLimitOrder = serumLimitOrders.shift();
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
} else {
|
|
792
|
+
while (
|
|
793
|
+
!cumulativeQuoteFilled.eq(amount) &&
|
|
794
|
+
(dlobLimitOrder || serumLimitOrder)
|
|
795
|
+
) {
|
|
796
|
+
const dlobLimitOrderPrice = dlobLimitOrder?.getPrice(
|
|
797
|
+
oraclePriceData,
|
|
798
|
+
slot
|
|
799
|
+
);
|
|
800
|
+
const serumLimitOrderPrice = serumLimitOrder
|
|
801
|
+
? new BN(serumLimitOrder[0] * PRICE_PRECISION.toNumber())
|
|
802
|
+
: undefined;
|
|
803
|
+
|
|
804
|
+
const useSerum = takerIsLong
|
|
805
|
+
? (serumLimitOrderPrice || BN_MAX).lt(dlobLimitOrderPrice || BN_MAX)
|
|
806
|
+
: (serumLimitOrderPrice || ZERO).gt(dlobLimitOrderPrice || ZERO);
|
|
807
|
+
|
|
808
|
+
if (!useSerum) {
|
|
809
|
+
if (dlobLimitOrder && usersToSkip.has(dlobLimitOrder.userAccount)) {
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
const quoteFilled = BN.min(
|
|
814
|
+
dlobLimitOrder.order.baseAssetAmount
|
|
815
|
+
.sub(dlobLimitOrder.order.baseAssetAmountFilled)
|
|
816
|
+
.mul(dlobLimitOrderPrice)
|
|
817
|
+
.div(basePrecision),
|
|
818
|
+
amount.sub(cumulativeQuoteFilled)
|
|
819
|
+
);
|
|
820
|
+
|
|
821
|
+
const baseFilled = quoteFilled
|
|
822
|
+
.mul(basePrecision)
|
|
823
|
+
.div(dlobLimitOrderPrice);
|
|
824
|
+
|
|
825
|
+
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
826
|
+
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
827
|
+
|
|
828
|
+
worstPrice = dlobLimitOrderPrice;
|
|
829
|
+
|
|
830
|
+
dlobLimitOrder = dlobLimitOrders.next().value;
|
|
831
|
+
} else {
|
|
832
|
+
const serumOrderBaseAmount = new BN(
|
|
833
|
+
serumLimitOrder[1] * basePrecision.toNumber()
|
|
834
|
+
);
|
|
835
|
+
const quoteFilled = BN.min(
|
|
836
|
+
serumOrderBaseAmount.mul(serumLimitOrderPrice).div(basePrecision),
|
|
837
|
+
amount.sub(cumulativeQuoteFilled)
|
|
838
|
+
);
|
|
839
|
+
|
|
840
|
+
const baseFilled = quoteFilled
|
|
841
|
+
.mul(basePrecision)
|
|
842
|
+
.div(serumLimitOrderPrice);
|
|
843
|
+
|
|
844
|
+
cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
|
|
845
|
+
cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
|
|
846
|
+
|
|
847
|
+
worstPrice = serumLimitOrderPrice;
|
|
848
|
+
|
|
849
|
+
serumLimitOrder = serumLimitOrders.shift();
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
const entryPrice = cumulativeQuoteFilled
|
|
855
|
+
.mul(basePrecision)
|
|
856
|
+
.div(cumulativeBaseFilled);
|
|
857
|
+
|
|
858
|
+
const priceImpact = entryPrice
|
|
859
|
+
.sub(bestPrice)
|
|
561
860
|
.mul(PRICE_PRECISION)
|
|
562
|
-
.div(
|
|
861
|
+
.div(bestPrice)
|
|
563
862
|
.abs();
|
|
564
863
|
|
|
565
|
-
return
|
|
864
|
+
return {
|
|
865
|
+
entryPrice,
|
|
866
|
+
priceImpact,
|
|
867
|
+
bestPrice,
|
|
868
|
+
worstPrice,
|
|
869
|
+
baseFilled: cumulativeBaseFilled,
|
|
870
|
+
quoteFilled: cumulativeQuoteFilled,
|
|
871
|
+
};
|
|
566
872
|
}
|