Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get latest hourly tick to compute final tick for megavault PnL. #2454

Merged
merged 1 commit into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,23 @@ import config from '../../../../src/config';

describe('vault-controller#V4', () => {
const latestBlockHeight: string = '25';
const currentBlockHeight: string = '9';
const currentHourBlockHeight: string = '10';
const currentDayBlockHeight: string = '9';
const twoHourBlockHeight: string = '7';
const almostTwoDayBlockHeight: string = '5';
const twoDayBlockHeight: string = '3';
const currentTime: DateTime = DateTime.utc().startOf('day').minus({ hour: 5 });
const latestTime: DateTime = currentTime.plus({ second: 5 });
const twoHoursAgo: DateTime = currentTime.minus({ hour: 2 });
const twoDaysAgo: DateTime = currentTime.minus({ day: 2 });
const almostTwoDaysAgo: DateTime = currentTime.minus({ hour: 47 });
const currentDay: DateTime = DateTime.utc().startOf('day').minus({ hour: 5 });
const currentHour: DateTime = currentDay.plus({ hour: 1 });
const latestTime: DateTime = currentDay.plus({ minute: 90 });
const twoHoursAgo: DateTime = currentDay.minus({ hour: 2 });
const twoDaysAgo: DateTime = currentDay.minus({ day: 2 });
const almostTwoDaysAgo: DateTime = currentDay.minus({ hour: 47 });
const initialFundingIndex: string = '10000';
const vault1Equity: number = 159500;
const vault2Equity: number = 10000;
const mainVaultEquity: number = 10000;
const vaultPnlHistoryHoursPrev: number = config.VAULT_PNL_HISTORY_HOURS;
const vaultPnlLastPnlWindowPrev: number = config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS;

beforeAll(async () => {
await dbHelpers.migrate();
Expand All @@ -52,6 +55,8 @@ describe('vault-controller#V4', () => {
beforeEach(async () => {
// Get a week of data for hourly pnl ticks.
config.VAULT_PNL_HISTORY_HOURS = 168;
// Use last 48 hours to get latest pnl tick for tests.
config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS = 48;
await testMocks.seedData();
await perpetualMarketRefresher.updatePerpetualMarkets();
await liquidityTierRefresher.updateLiquidityTiers();
Expand All @@ -68,8 +73,8 @@ describe('vault-controller#V4', () => {
}),
BlockTable.create({
...testConstants.defaultBlock,
time: currentTime.toISO(),
blockHeight: currentBlockHeight,
time: currentDay.toISO(),
blockHeight: currentDayBlockHeight,
}),
BlockTable.create({
...testConstants.defaultBlock,
Expand All @@ -81,6 +86,11 @@ describe('vault-controller#V4', () => {
time: almostTwoDaysAgo.toISO(),
blockHeight: almostTwoDayBlockHeight,
}),
BlockTable.create({
...testConstants.defaultBlock,
time: currentHour.toISO(),
blockHeight: currentHourBlockHeight,
}),
]);
await SubaccountTable.create(testConstants.vaultSubaccount);
await SubaccountTable.create({
Expand Down Expand Up @@ -114,6 +124,7 @@ describe('vault-controller#V4', () => {
afterEach(async () => {
await dbHelpers.clearData();
config.VAULT_PNL_HISTORY_HOURS = vaultPnlHistoryHoursPrev;
config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS = vaultPnlLastPnlWindowPrev;
});

it('Get /megavault/historicalPnl with no vault subaccounts', async () => {
Expand All @@ -126,13 +137,14 @@ describe('vault-controller#V4', () => {
});

it.each([
['no resolution', '', [1, 2]],
['daily resolution', '?resolution=day', [1, 2]],
['hourly resolution', '?resolution=hour', [1, 2, 3]],
['no resolution', '', [1, 2], 4],
['daily resolution', '?resolution=day', [1, 2], 4],
['hourly resolution', '?resolution=hour', [1, 2, 3, 4], 4],
])('Get /megavault/historicalPnl with single vault subaccount (%s)', async (
_name: string,
queryParam: string,
expectedTicksIndex: number[],
finalTickIndex: number,
) => {
await VaultTable.create({
...testConstants.defaultVault,
Expand All @@ -141,7 +153,7 @@ describe('vault-controller#V4', () => {
});
const createdPnlTicks: PnlTicksFromDatabase[] = await createPnlTicks();
const finalTick: PnlTicksFromDatabase = {
...createdPnlTicks[expectedTicksIndex[expectedTicksIndex.length - 1]],
...createdPnlTicks[finalTickIndex],
equity: Big(vault1Equity).toFixed(),
blockHeight: latestBlockHeight,
blockTime: latestTime.toISO(),
Expand All @@ -164,14 +176,14 @@ describe('vault-controller#V4', () => {
});

it.each([
['no resolution', '', [1, 2], [undefined, 6], [9, 10]],
['daily resolution', '?resolution=day', [1, 2], [undefined, 6], [9, 10]],
['no resolution', '', [1, 2], [undefined, 7], [11, 12]],
['daily resolution', '?resolution=day', [1, 2], [undefined, 7], [11, 12]],
[
'hourly resolution',
'?resolution=hour',
[1, undefined, 2, 3],
[undefined, 5, 6, 7],
[9, undefined, 10, 11],
[1, undefined, 2, 3, 4],
[undefined, 6, 7, 8, 9],
[11, undefined, 12, 13, 14],
],
])('Get /megavault/historicalPnl with 2 vault subaccounts and main subaccount (%s)', async (
_name: string,
Expand Down Expand Up @@ -212,7 +224,8 @@ describe('vault-controller#V4', () => {

const expectedPnlTickBase: any = {
equity: (parseFloat(testConstants.defaultPnlTick.equity) * 3).toString(),
totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) * 3).toString(),
// total pnl should be fetched from latest hourly pnl tick.
totalPnl: (parseFloat(testConstants.defaultPnlTick.totalPnl) * 4).toString(),
netTransfers: (parseFloat(testConstants.defaultPnlTick.netTransfers) * 3).toString(),
};
const finalTick: PnlTicksFromDatabase = {
Expand Down Expand Up @@ -268,7 +281,7 @@ describe('vault-controller#V4', () => {
it.each([
['no resolution', '', [1, 2]],
['daily resolution', '?resolution=day', [1, 2]],
['hourly resolution', '?resolution=hour', [1, 2, 3]],
['hourly resolution', '?resolution=hour', [1, 2, 3, 4]],
])('Get /vaults/historicalPnl with single vault subaccount (%s)', async (
_name: string,
queryParam: string,
Expand Down Expand Up @@ -306,9 +319,9 @@ describe('vault-controller#V4', () => {
});

it.each([
['no resolution', '', [1, 2], [5, 6]],
['daily resolution', '?resolution=day', [1, 2], [5, 6]],
['hourly resolution', '?resolution=hour', [1, 2, 3], [5, 6, 7]],
['no resolution', '', [1, 2], [6, 7]],
['daily resolution', '?resolution=day', [1, 2], [6, 7]],
['hourly resolution', '?resolution=hour', [1, 2, 3, 4], [6, 7, 8, 9]],
])('Get /vaults/historicalPnl with 2 vault subaccounts (%s)', async (
_name: string,
queryParam: string,
Expand Down Expand Up @@ -526,9 +539,16 @@ describe('vault-controller#V4', () => {
}),
PnlTicksTable.create({
...testConstants.defaultPnlTick,
blockTime: currentTime.toISO(),
createdAt: currentTime.toISO(),
blockHeight: currentBlockHeight,
blockTime: currentDay.toISO(),
createdAt: currentDay.toISO(),
blockHeight: currentDayBlockHeight,
}),
PnlTicksTable.create({
...testConstants.defaultPnlTick,
totalPnl: (2 * parseFloat(testConstants.defaultPnlTick.totalPnl)).toString(),
blockTime: currentHour.toISO(),
createdAt: currentHour.toISO(),
blockHeight: currentHourBlockHeight,
}),
PnlTicksTable.create({
...testConstants.defaultPnlTick,
Expand All @@ -551,9 +571,16 @@ describe('vault-controller#V4', () => {
PnlTicksTable.create({
...testConstants.defaultPnlTick,
subaccountId: testConstants.vaultSubaccountId,
blockTime: currentTime.toISO(),
createdAt: currentTime.toISO(),
blockHeight: currentBlockHeight,
blockTime: currentDay.toISO(),
createdAt: currentDay.toISO(),
blockHeight: currentDayBlockHeight,
}),
PnlTicksTable.create({
...testConstants.defaultPnlTick,
subaccountId: testConstants.vaultSubaccountId,
blockTime: currentHour.toISO(),
createdAt: currentHour.toISO(),
blockHeight: currentHourBlockHeight,
}),
]);

Expand All @@ -580,9 +607,16 @@ describe('vault-controller#V4', () => {
PnlTicksTable.create({
...testConstants.defaultPnlTick,
subaccountId: MEGAVAULT_SUBACCOUNT_ID,
blockTime: currentTime.toISO(),
createdAt: currentTime.toISO(),
blockHeight: currentBlockHeight,
blockTime: currentDay.toISO(),
createdAt: currentDay.toISO(),
blockHeight: currentDayBlockHeight,
}),
PnlTicksTable.create({
...testConstants.defaultPnlTick,
subaccountId: MEGAVAULT_SUBACCOUNT_ID,
blockTime: currentHour.toISO(),
createdAt: currentHour.toISO(),
blockHeight: currentHourBlockHeight,
}),
]);
createdTicks.push(...mainSubaccountTicks);
Expand Down
1 change: 1 addition & 0 deletions indexer/services/comlink/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const configSchema = {
// Vaults config
VAULT_PNL_HISTORY_DAYS: parseInteger({ default: 90 }),
VAULT_PNL_HISTORY_HOURS: parseInteger({ default: 72 }),
VAULT_LATEST_PNL_TICK_WINDOW_HOURS: parseInteger({ default: 1 }),
vincentwschau marked this conversation as resolved.
Show resolved Hide resolved
};

////////////////////////////////////////////////////////////////////////////////
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,19 @@ class VaultController extends Controller {
vaultPositions,
latestBlock,
mainSubaccountEquity,
latestPnlTick,
] : [
PnlTicksFromDatabase[],
Map<string, VaultPosition>,
BlockFromDatabase,
string,
PnlTicksFromDatabase | undefined,
] = await Promise.all([
getVaultSubaccountPnlTicks(vaultSubaccountIdsWithMainSubaccount, getResolution(resolution)),
getVaultPositions(vaultSubaccounts),
BlockTable.getLatest(),
getMainSubaccountEquity(),
getLatestPnlTick(vaultSubaccountIdsWithMainSubaccount),
]);

// aggregate pnlTicks for all vault subaccounts grouped by blockHeight
Expand All @@ -105,6 +108,7 @@ class VaultController extends Controller {
currentEquity,
filterOutIntervalTicks(aggregatedPnlTicks, getResolution(resolution)),
latestBlock,
latestPnlTick,
);

return {
Expand Down Expand Up @@ -458,7 +462,17 @@ function getPnlTicksWithCurrentTick(
equity: string,
pnlTicks: PnlTicksFromDatabase[],
latestBlock: BlockFromDatabase,
latestTick: PnlTicksFromDatabase | undefined = undefined,
): PnlTicksFromDatabase[] {
if (latestTick !== undefined) {
return pnlTicks.concat({
...latestTick,
equity,
blockHeight: latestBlock.blockHeight,
blockTime: latestBlock.time,
createdAt: latestBlock.time,
});
}
vincentwschau marked this conversation as resolved.
Show resolved Hide resolved
if (pnlTicks.length === 0) {
return [];
}
Expand All @@ -472,6 +486,23 @@ function getPnlTicksWithCurrentTick(
return pnlTicks.concat([currentTick]);
}

export async function getLatestPnlTick(
vaultSubaccountIds: string[],
): Promise<PnlTicksFromDatabase | undefined> {
const pnlTicks: PnlTicksFromDatabase[] = await PnlTicksTable.getPnlTicksAtIntervals(
PnlTickInterval.hour,
config.VAULT_LATEST_PNL_TICK_WINDOW_HOURS * 60 * 60,
vaultSubaccountIds,
);
// Aggregate and get pnl tick closest to the hour
const aggregatedTicks: PnlTicksFromDatabase[] = aggregateHourlyPnlTicks(pnlTicks);
const filteredTicks: PnlTicksFromDatabase[] = filterOutIntervalTicks(
aggregatedTicks,
PnlTickInterval.hour,
);
return _.maxBy(filteredTicks, 'blockTime');
}

/**
* Takes in an array of PnlTicks and filters out the closest pnl tick per interval.
* @param pnlTicks Array of pnl ticks.
Expand Down
Loading