Skip to content

Commit

Permalink
Merge branch 'master' into develop
Browse files Browse the repository at this point in the history
Merge master into develop
  • Loading branch information
mangrove-automation authored Jan 11, 2024
2 parents aad34ee + ac46af2 commit 79e22b3
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 130 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Next version

- feat: Moved MangroveJsDeploy from mangrove-strats to this package. Renamed script to EmptyChainDeployer
- fix: rounding when deducing tick from price for LiquidityProvider

# 2.0.0

Expand Down
4 changes: 2 additions & 2 deletions src/liquidityProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ class LiquidityProvider {
} else if ("price" in p) {
// deduce tick & gives from volume & price
const price = Big(p.price);
// round down to ensure price is not exceeded
tick = tickPriceHelper.tickFromPrice(price, "roundDown");
// round up to ensure we get at least the tick we want
tick = tickPriceHelper.tickFromPrice(price, "roundUp");
if (p.ba === "bids") {
gives = Big(p.volume).mul(price);
} else {
Expand Down
153 changes: 46 additions & 107 deletions src/util/trade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,50 +25,55 @@ class Trade {
tradeEventManagement = new TradeEventManagement();

/**
* Get raw parameters to send to Mangrove for a buy order for the given trade and market parameters.
* Get raw parameters to send to Mangrove for a buy or sell order for the given trade and market parameters.
*/
getParamsForBuy(
getParamsForTrade(
params: Market.TradeParams,
market: Market.KeyResolvedForCalculation,
bs: Market.BS,
) {
// validate parameters and setup tickPriceHelper
let fillVolume: Big, maxTick: number, fillWants: boolean;
let fillVolume: Big,
maxTick: number,
fillWants: boolean = bs === "buy";
const ba = this.bsToBa(bs);
const slippage = this.validateSlippage(params.slippage);
const tickPriceHelper = new TickPriceHelper("asks", market);
const tickPriceHelper = new TickPriceHelper(ba, market);
if ("limitPrice" in params) {
if (Big(params.limitPrice).lte(0)) {
throw new Error("Cannot buy at or below price 0");
}
const priceWithSlippage = this.adjustForSlippage(
const limitPriceWithSlippage = this.adjustForSlippage(
Big(params.limitPrice),
slippage,
"buy",
bs,
);
// round down to not exceed the price
maxTick = tickPriceHelper.tickFromPrice(priceWithSlippage, "roundDown");
maxTick = tickPriceHelper.tickFromPrice(
limitPriceWithSlippage,
"roundDown",
);
if ("volume" in params) {
fillVolume = Big(params.volume);
fillWants = true;
} else {
fillVolume = Big(params.total);
fillWants = false;
fillWants = !fillWants;
}
} else if ("maxTick" in params) {
// in this case, we're merely asking to get the tick adjusted for slippage
fillVolume = Big(params.fillVolume);
fillWants = params.fillWants ?? true;
fillWants = params.fillWants ?? fillWants;
if (slippage > 0) {
// round down to not exceed the price
// round down to not exceed the price when buying, and up to get at least price for when selling
const limitPrice = tickPriceHelper.priceFromTick(
params.maxTick,
"roundDown",
bs === "buy" ? "roundDown" : "roundUp",
);
const limitPriceWithSlippage = this.adjustForSlippage(
limitPrice,
slippage,
"buy",
bs,
);
// round down to not exceed the price
// round down to not exceed the price expectations
maxTick = tickPriceHelper.tickFromPrice(
limitPriceWithSlippage,
"roundDown",
Expand All @@ -78,26 +83,32 @@ class Trade {
maxTick = params.maxTick;
}
} else {
const givesWithSlippage = this.adjustForSlippage(
Big(params.gives),
slippage,
"buy",
);
fillWants = params.fillWants ?? true;
fillVolume = fillWants ? Big(params.wants) : givesWithSlippage;
// round down to not exceed price expectations
maxTick = tickPriceHelper.tickFromVolumes(
givesWithSlippage,
params.wants,
"roundDown",
);
let wants = Big(params.wants);
let gives = Big(params.gives);
if (bs === "buy") {
gives = this.adjustForSlippage(gives, slippage, bs);
} else {
wants = this.adjustForSlippage(wants, slippage, bs);
}
fillWants = params.fillWants ?? fillWants;
fillVolume = fillWants ? wants : gives;
// round down to not exceed the price expectations
maxTick = tickPriceHelper.tickFromVolumes(gives, wants, "roundDown");
}

return {
maxTick,
fillVolume: fillWants
? market.base.toUnits(fillVolume)
: market.quote.toUnits(fillVolume),
? Market.getOutboundInbound(
ba,
market.base,
market.quote,
).outbound_tkn.toUnits(fillVolume)
: Market.getOutboundInbound(
ba,
market.base,
market.quote,
).inbound_tkn.toUnits(fillVolume),
fillWants: fillWants,
};
}
Expand All @@ -118,79 +129,6 @@ class Trade {
return value.mul(100 + adjustment).div(100);
}

/**
* Get raw parameters to send to Mangrove for a sell order for the given trade and market parameters.
*/
getParamsForSell(
params: Market.TradeParams,
market: Market.KeyResolvedForCalculation,
) {
let fillVolume: Big, maxTick: number, fillWants: boolean;
const slippage = this.validateSlippage(params.slippage);
const tickPriceHelper = new TickPriceHelper("bids", market);
if ("limitPrice" in params) {
if (Big(params.limitPrice).lte(0)) {
throw new Error("Cannot buy at or below price 0");
}
const priceWithSlippage = this.adjustForSlippage(
Big(params.limitPrice),
slippage,
"sell",
);
// round down to not exceed the price
maxTick = tickPriceHelper.tickFromPrice(priceWithSlippage, "roundDown");
if ("volume" in params) {
fillVolume = Big(params.volume);
fillWants = false;
} else {
fillVolume = Big(params.total);
fillWants = true;
}
} else if ("maxTick" in params) {
// in this case, we're merely asking to get the tick adjusted for slippage
fillVolume = Big(params.fillVolume);
fillWants = params.fillWants ?? false;
if (slippage > 0) {
// Round up since a higher price is better for sell
const limitPrice = tickPriceHelper.priceFromTick(
params.maxTick,
"roundUp",
);
const priceWithSlippage = this.adjustForSlippage(
limitPrice,
slippage,
"sell",
);
// round down to not exceed the price expectations
maxTick = tickPriceHelper.tickFromPrice(priceWithSlippage, "roundDown");
} else {
maxTick = params.maxTick;
}
} else {
const wantsWithSlippage = this.adjustForSlippage(
Big(params.wants),
slippage,
"sell",
);
fillWants = params.fillWants ?? false;
fillVolume = fillWants ? wantsWithSlippage : Big(params.gives);
// round down to not exceed the price expectations
maxTick = tickPriceHelper.tickFromVolumes(
params.gives,
wantsWithSlippage,
"roundDown",
);
}

return {
fillVolume: fillWants
? market.quote.toUnits(fillVolume)
: market.base.toUnits(fillVolume),
maxTick,
fillWants: fillWants,
};
}

validateSlippage = (slippage = 0) => {
if (typeof slippage === "undefined") {
return 0;
Expand Down Expand Up @@ -254,10 +192,11 @@ class Trade {
* @returns raw parameters for a market order to send to Mangrove
*/
getRawParams(bs: Market.BS, params: Market.TradeParams, market: Market) {
const { maxTick, fillVolume, fillWants } =
bs === "buy"
? this.getParamsForBuy(params, market)
: this.getParamsForSell(params, market);
const { maxTick, fillVolume, fillWants } = this.getParamsForTrade(
params,
market,
bs,
);
const restingOrderParams =
"restingOrder" in params ? params.restingOrder : null;

Expand Down
5 changes: 4 additions & 1 deletion test/integration/restingOrder.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@ describe("RestingOrder", () => {
fund: askProvision,
});
await meAsLP.newAsk({
price: 10 / 10,
// Set price so that takers will hit it with a price of 1
price: market
.getSemibook("asks")
.tickPriceHelper.coercePrice(1, "roundDown"),
volume: 10,
fund: askProvision,
});
Expand Down
12 changes: 6 additions & 6 deletions test/unit/liquidityProvider.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe("Liquidity provider unit tests suite", () => {
);
assert.deepStrictEqual(gives, Big(1));
assert.deepStrictEqual(fund, undefined);
assert.deepStrictEqual(tick, -276400);
assert.deepStrictEqual(tick, -276300);
});

it("normalizeOfferParams, with volume and price 1, as bids", async function () {
Expand All @@ -92,7 +92,7 @@ describe("Liquidity provider unit tests suite", () => {
);
assert.deepStrictEqual(gives, Big(1));
assert.deepStrictEqual(fund, undefined);
assert.deepStrictEqual(tick, 276324);
assert.deepStrictEqual(tick, 276325);
});

it("normalizeOfferParams, with volume and price 2, as asks", async function () {
Expand All @@ -110,7 +110,7 @@ describe("Liquidity provider unit tests suite", () => {
);
assert.deepStrictEqual(gives, Big(1));
assert.deepStrictEqual(fund, undefined);
assert.deepStrictEqual(tick, 6931);
assert.deepStrictEqual(tick, 6932);
});

it("normalizeOfferParams, with volume and price 2, as bids", async function () {
Expand All @@ -128,7 +128,7 @@ describe("Liquidity provider unit tests suite", () => {
);
assert.deepStrictEqual(gives, Big(2));
assert.deepStrictEqual(fund, undefined);
assert.deepStrictEqual(tick, -6932);
assert.deepStrictEqual(tick, -6931);
});

it("normalizeOfferParams, with volume and price 2, as asks", async function () {
Expand All @@ -146,7 +146,7 @@ describe("Liquidity provider unit tests suite", () => {
);
assert.deepStrictEqual(gives, Big(1));
assert.deepStrictEqual(fund, undefined);
assert.deepStrictEqual(tick, 6931);
assert.deepStrictEqual(tick, 6932);
});

it("normalizeOfferParams, with volume and price 2, as bids", async function () {
Expand All @@ -164,7 +164,7 @@ describe("Liquidity provider unit tests suite", () => {
);
assert.deepStrictEqual(gives, Big(2));
assert.deepStrictEqual(fund, undefined);
assert.deepStrictEqual(tick, -6932);
assert.deepStrictEqual(tick, -6931);
});

it("normalizeOfferParams, with gives and wants, as bids", async function () {
Expand Down
Loading

0 comments on commit 79e22b3

Please sign in to comment.