Skip to content

Commit

Permalink
Implemented position exposure cap on floatingMaker
Browse files Browse the repository at this point in the history
Trivial implementation, see comments on the code for details.

This addresses issue #65.
  • Loading branch information
ricardojmendez committed Sep 5, 2023
1 parent 725561c commit a29d7d6
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 3 deletions.
2 changes: 1 addition & 1 deletion example.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ botConfigs:
metricsPort: 9669
intervalMs: 7500
orderOffset: 95
orderSize: 5
orderSize: 4
# If subAccountId is set, it should also be included on the subaccounts config above
subAccountId: 1
perpMarketIndices:
Expand Down
62 changes: 60 additions & 2 deletions src/bots/floatingMaker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ import {
PositionDirection,
OrderType,
BASE_PRECISION,
QUOTE_PRECISION,
convertToNumber,
PRICE_PRECISION,
Order,
PerpPosition,
User,
ZERO,
} from '@drift-labs/sdk';
import { Mutex, tryAcquire, E_ALREADY_LOCKED } from 'async-mutex';

Expand Down Expand Up @@ -66,6 +69,8 @@ export class FloatingPerpMakerBot implements Bot {

private intervalIds: Array<NodeJS.Timer> = [];

private user: User;

// metrics
private metricsInitialized = false;
private metricsPort?: number;
Expand Down Expand Up @@ -125,6 +130,7 @@ export class FloatingPerpMakerBot implements Bot {
);
}
this.driftClient.switchActiveUser(this.subAccountId);
this.user = this.driftClient.getUser();

this.marketIndices = new Set<number>(config.perpMarketIndices);

Expand Down Expand Up @@ -325,6 +331,58 @@ export class FloatingPerpMakerBot implements Bot {

// cancel orders if not quoting both sides of the market
let placeNewOrders = openOrders.length === 0;
logger.info(
`Orders open: ${openOrders.length}. Placing? ${placeNewOrders}`
);

// Skew order size based on total exposure and asset value
const totalAssetValue = convertToNumber(
this.user.getSpotMarketAssetValue(
0, // USDC
'Maintenance',
true
),
QUOTE_PRECISION
);
const position = this.user.getPerpPosition(marketIndex);
const posAmount = convertToNumber(
position?.baseAssetAmount ?? ZERO,
BASE_PRECISION
);
const perpValue = convertToNumber(
this.user.getPerpPositionValue(marketIndex, oracle),
QUOTE_PRECISION
);
const exposure = perpValue / totalAssetValue;
const pctExpAllowed =
1 - perpValue / (totalAssetValue * this.MAX_POSITION_EXPOSURE);
// Yes, this will give a LONG direction when there's no position. It makes no difference,
// because in that case the exposure will be 0 and it'll be evenly split.
const exposureDir =
Math.sign(posAmount) >= 0
? PositionDirection.LONG
: PositionDirection.SHORT;
logger.info(
`PerpPosition value: $${perpValue} with ${posAmount}. Exposure: ${exposure}. Allowance used: ${pctExpAllowed}`
);

// Calculate the order size.
//
// Notice that if this ever gets too small - say, we have hit the exposure
// allowance and need to skew it to one side - order placing will barf.
//
// How to handle this is left as an exercise. You may only want to quote one
// side and keep that order open for a while, or keep canceling it and
// moving it closer to the oracle (see openOrders.length comparison below).
const pctCurrent = pctExpAllowed / 2;
const orderSizeCurrent = pctCurrent * (this.orderSize * 2);
const orderSizeOther = (1 - pctCurrent) * (this.orderSize * 2);
const orderSizeLong =
exposureDir == PositionDirection.LONG ? orderSizeCurrent : orderSizeOther;
const orderSizeShort =
exposureDir == PositionDirection.SHORT
? orderSizeCurrent
: orderSizeOther;

if (openOrders.length > 0 && openOrders.length != 2) {
// cancel orders
Expand Down Expand Up @@ -362,7 +420,7 @@ export class FloatingPerpMakerBot implements Bot {
marketIndex: marketIndex,
orderType: OrderType.LIMIT,
direction: PositionDirection.LONG,
baseAssetAmount: BASE_PRECISION.mul(new BN(this.orderSize)),
baseAssetAmount: new BN(orderSizeLong * BASE_PRECISION.toNumber()),
oraclePriceOffset: oracleBidSpread
.mul(biasNum)
.div(biasDenom)
Expand All @@ -373,7 +431,7 @@ export class FloatingPerpMakerBot implements Bot {
marketIndex: marketIndex,
orderType: OrderType.LIMIT,
direction: PositionDirection.SHORT,
baseAssetAmount: BASE_PRECISION.mul(new BN(this.orderSize)),
baseAssetAmount: new BN(orderSizeShort * BASE_PRECISION.toNumber()),
oraclePriceOffset: oracleAskSpread
.mul(biasNum)
.div(biasDenom)
Expand Down

0 comments on commit a29d7d6

Please sign in to comment.