Skip to content

Commit 0694869

Browse files
llamalmnoahlitvin
andauthored
Add cumulative index to cache
* Add cumulative index to cache * add isCumulative field to the markets * use the new isCumulative market param * fix * fix fixture * missing detail --------- Co-authored-by: Noah Litvin <[email protected]>
1 parent 2bef300 commit 0694869

File tree

12 files changed

+101
-63
lines changed

12 files changed

+101
-63
lines changed

packages/api/schema.graphql

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type MarketType {
3131
deployTxnBlockNumber: Int
3232
epochs: [EpochType!]!
3333
id: ID!
34+
isCumulative: Boolean!
3435
isYin: Boolean!
3536
owner: String
3637
resource: ResourceType

packages/api/src/controllers/market.ts

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export const initializeMarket = async (marketInfo: MarketInfo) => {
9999
updatedMarket.address = marketInfo.deployment.address;
100100
updatedMarket.vaultAddress = marketInfo.vaultAddress;
101101
updatedMarket.isYin = marketInfo.isYin;
102+
updatedMarket.isCumulative = marketInfo.isCumulative;
102103
updatedMarket.deployTxnBlockNumber = Number(
103104
marketInfo.deployment.deployTxnBlockNumber
104105
);

packages/api/src/fixtures.ts

+2
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,15 @@ const addMarketYinYang = async (
9191
marketChainId: chainId,
9292
resource,
9393
isYin: true,
94+
isCumulative: false,
9495
},
9596
{
9697
deployment: yang,
9798
vaultAddress: yangVault.address,
9899
marketChainId: chainId,
99100
resource,
100101
isYin: false,
102+
isCumulative: false,
101103
}
102104
);
103105
}

packages/api/src/graphql/resolvers/mappers.ts

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const mapMarketToType = (market: Market): MarketType => ({
2020
vaultAddress: market.vaultAddress,
2121
chainId: market.chainId,
2222
isYin: market.isYin,
23+
isCumulative: market.isCumulative,
2324
epochs: market.epochs?.map(mapEpochToType) || [],
2425
resource: market.resource ? mapResourceToType(market.resource) : null,
2526
deployTimestamp: market.deployTimestamp,

packages/api/src/graphql/types/MarketType.ts

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ export class MarketType {
2020
@Field(() => Boolean)
2121
isYin: boolean;
2222

23+
@Field(() => Boolean)
24+
isCumulative: boolean;
25+
2326
@Field(() => [EpochType])
2427
epochs: EpochType[];
2528

packages/api/src/interfaces.ts

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ export interface MarketInfo {
125125
deployment: Deployment;
126126
vaultAddress: string;
127127
isYin: boolean;
128+
isCumulative: boolean;
128129
marketChainId: number;
129130
resource: {
130131
name: string;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { MigrationInterface, QueryRunner } from 'typeorm';
2+
3+
export class Migration1742424541642 implements MigrationInterface {
4+
name = 'Migration1742424541642';
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(
8+
`ALTER TABLE "market" ADD "isCumulative" boolean NOT NULL DEFAULT false`
9+
);
10+
}
11+
12+
public async down(queryRunner: QueryRunner): Promise<void> {
13+
await queryRunner.query(`ALTER TABLE "market" DROP COLUMN "isCumulative"`);
14+
}
15+
}

packages/api/src/models/Market.ts

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export class Market {
4343
@Column({ type: 'boolean', default: false })
4444
isYin: boolean;
4545

46+
@Column({ type: 'boolean', default: false })
47+
isCumulative: boolean;
48+
4649
@Column({ type: 'integer' })
4750
@Index()
4851
chainId: number;

packages/api/src/performance/helper.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as fs from 'fs';
33
import * as path from 'path';
44
import { encode, decode } from '@msgpack/msgpack';
55

6-
const FILE_VERSION = 3;
6+
const FILE_VERSION = 4;
77

88
export async function saveStorageToFile(
99
storage: IntervalStore,

packages/api/src/performance/resourcePerformance.ts

+49-46
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
StorageData,
1515
TrailingAvgData,
1616
CandleData,
17+
ReducedIndexData,
1718
} from './types';
1819
import { MoreThan } from 'typeorm';
1920
import { TIME_INTERVALS } from 'src/fixtures';
@@ -558,13 +559,14 @@ export class ResourcePerformance {
558559

559560
if (existingIndex === -1) {
560561
// Create a new placeholder
561-
resourceStore.data.push({
562+
const datapoint: ReducedCandleData = {
562563
t: item.timestamp,
563564
o: price.toString(),
564565
h: price.toString(),
565566
l: price.toString(),
566567
c: price.toString(),
567-
});
568+
};
569+
resourceStore.data.push(datapoint);
568570

569571
resourceStore.metadata.push({
570572
st: itemStartTime,
@@ -713,13 +715,12 @@ export class ResourcePerformance {
713715

714716
if (!isLastStoredItem) {
715717
// Create a new placeholder
716-
piStore.data.push({
718+
const datapoint: ReducedIndexData = {
717719
t: itemStartTime,
718-
o: '0',
719-
h: '0',
720-
l: '0',
720+
v: '0',
721721
c: '0',
722-
});
722+
};
723+
piStore.data.push(datapoint);
723724

724725
piStore.metadata.push({
725726
st: item.timestamp,
@@ -764,15 +765,12 @@ export class ResourcePerformance {
764765
// Update the placeholder with final values
765766
piStore.data[currentPlaceholderIndex] = {
766767
t: piStore.data[currentPlaceholderIndex].t,
767-
o: avgPrice.toString(),
768-
h: avgPrice.toString(),
769-
l: avgPrice.toString(),
770-
c: avgPrice.toString(),
768+
v: avgPrice.toString(), // value
769+
c: fixedUsed.toString(), // cumulative
771770
};
772771

773772
piStore.metadata[currentPlaceholderIndex] = {
774-
st:
775-
piStore.metadata[currentPlaceholderIndex].st,
773+
st: piStore.metadata[currentPlaceholderIndex].st,
776774
et: item.timestamp,
777775
u: ripd.used.toString(),
778776
f: ripd.feePaid.toString(),
@@ -799,10 +797,8 @@ export class ResourcePerformance {
799797
// Create a new placeholder
800798
piStore.data.push({
801799
t: itemStartTime,
802-
o: avgPrice.toString(),
803-
h: avgPrice.toString(),
804-
l: avgPrice.toString(),
805-
c: avgPrice.toString(),
800+
v: avgPrice.toString(),
801+
c: fixedUsed.toString(),
806802
});
807803

808804
piStore.metadata.push({
@@ -962,8 +958,7 @@ export class ResourcePerformance {
962958
};
963959

964960
ptStore.metadata[currentPlaceholderIndex] = {
965-
st:
966-
ptStore.metadata[currentPlaceholderIndex].st,
961+
st: ptStore.metadata[currentPlaceholderIndex].st,
967962
et: item.timestamp,
968963
u: rtpd.used.toString(),
969964
f: rtpd.feePaid.toString(),
@@ -1072,18 +1067,17 @@ export class ResourcePerformance {
10721067
const pmStore = this.persistentStorage[interval].marketStore[epoch.id];
10731068

10741069
// Create a placeholder in the store
1075-
const itemStartTime = this.startOfCurrentInterval(
1076-
item.t,
1077-
interval
1078-
);
1070+
const itemStartTime = this.startOfCurrentInterval(item.t, interval);
10791071

10801072
// Check if we already have an item for this interval
10811073
const lastStoreIndex =
10821074
pmStore.data.length > 0 ? pmStore.data.length - 1 : undefined;
10831075

10841076
// Get cached data from the latest stored item
10851077
if (lastStoreIndex !== undefined) {
1086-
const previousData = pmStore.data[lastStoreIndex];
1078+
const previousData = pmStore.data[
1079+
lastStoreIndex
1080+
] as ReducedCandleData;
10871081
rmpd.open = BigInt(previousData.o);
10881082
rmpd.high = BigInt(previousData.h);
10891083
rmpd.low = BigInt(previousData.l);
@@ -1131,15 +1125,11 @@ export class ResourcePerformance {
11311125
rmpd.close = itemValueBn;
11321126

11331127
// Create a placeholder for the next interval
1134-
const itemStartTime = this.startOfCurrentInterval(
1135-
item.t,
1136-
interval
1137-
);
1128+
const itemStartTime = this.startOfCurrentInterval(item.t, interval);
11381129

11391130
// Check if we already have an item for this interval
11401131
const existingIndex = pmStore.data.findIndex(
1141-
(d) =>
1142-
d.t >= itemStartTime && d.t < rmpd.nextTimestamp
1132+
(d) => d.t >= itemStartTime && d.t < rmpd.nextTimestamp
11431133
);
11441134

11451135
if (existingIndex === -1 && !isEndOfEpoch) {
@@ -1172,14 +1162,18 @@ export class ResourcePerformance {
11721162
throw new Error(`Epoch not found for ${chainId}-${address}-${epoch}`);
11731163
}
11741164

1175-
return theEpoch.id;
1165+
return {
1166+
id: theEpoch.id,
1167+
isCumulative: theEpoch.market.isCumulative,
1168+
};
11761169
}
11771170

11781171
getResourcePrices(from: number, to: number, interval: number) {
11791172
this.checkInterval(interval);
11801173

11811174
return this.getPricesFromArray(
1182-
this.persistentStorage[interval].resourceStore.data,
1175+
this.persistentStorage[interval].resourceStore
1176+
.data as ReducedCandleData[],
11831177
from,
11841178
to,
11851179
interval
@@ -1195,17 +1189,27 @@ export class ResourcePerformance {
11951189
epoch: string
11961190
) {
11971191
this.checkInterval(interval);
1198-
const epochId = this.getEpochId(chainId, address, epoch);
1192+
const { id: epochId, isCumulative } = this.getEpochId(
1193+
chainId,
1194+
address,
1195+
epoch
1196+
);
11991197
if (!this.persistentStorage[interval].indexStore[epochId]) {
12001198
return [];
12011199
}
1202-
return this.getPricesFromArray(
1203-
this.persistentStorage[interval].indexStore[epochId].data,
1204-
from,
1205-
to,
1206-
interval,
1207-
false
1208-
);
1200+
1201+
const indexDatapoints = (
1202+
this.persistentStorage[interval].indexStore[epochId]
1203+
.data as ReducedIndexData[]
1204+
).map((d) => ({
1205+
t: d.t,
1206+
o: isCumulative ? d.c : d.v,
1207+
h: isCumulative ? d.c : d.v,
1208+
l: isCumulative ? d.c : d.v,
1209+
c: isCumulative ? d.c : d.v,
1210+
}));
1211+
1212+
return this.getPricesFromArray(indexDatapoints, from, to, interval, false);
12091213
}
12101214

12111215
getTrailingAvgPrices(
@@ -1218,7 +1222,7 @@ export class ResourcePerformance {
12181222
return this.getPricesFromArray(
12191223
this.persistentStorage[interval].trailingAvgStore[
12201224
trailingAvgTime.toString()
1221-
].data,
1225+
].data as ReducedCandleData[],
12221226
from,
12231227
to,
12241228
interval
@@ -1234,13 +1238,14 @@ export class ResourcePerformance {
12341238
epoch: string
12351239
) {
12361240
this.checkInterval(interval);
1237-
const epochId = this.getEpochId(chainId, address, epoch);
1241+
const { id: epochId } = this.getEpochId(chainId, address, epoch);
12381242
if (!this.persistentStorage[interval].marketStore[epochId]) {
12391243
return [];
12401244
}
12411245

12421246
const prices = await this.getPricesFromArray(
1243-
this.persistentStorage[interval].marketStore[epochId].data,
1247+
this.persistentStorage[interval].marketStore[epochId]
1248+
.data as ReducedCandleData[],
12441249
from,
12451250
to,
12461251
interval,
@@ -1326,9 +1331,7 @@ export class ResourcePerformance {
13261331

13271332
// TODO: Use pointer to find the start and end indices
13281333
// Since prices are ordered by timestamp, we can find the start and end indices
1329-
let startIndex = prices.findIndex(
1330-
(price) => price.t >= timeWindow.from
1331-
);
1334+
let startIndex = prices.findIndex((price) => price.t >= timeWindow.from);
13321335
if (startIndex === -1) startIndex = prices.length;
13331336

13341337
let endIndex = prices.length;

packages/api/src/performance/types.ts

+22-16
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
export type ReducedCandleData = {
2-
t: number;
3-
o: string;
4-
h: string;
5-
l: string;
6-
c: string;
2+
t: number; // timestamp
3+
o: string; // open
4+
h: string; // high
5+
l: string; // low
6+
c: string; // close
7+
};
8+
9+
export type ReducedIndexData = {
10+
t: number; // timestamp
11+
v: string; // value
12+
c: string; // cumulative
713
};
814

915
export type CandleData = {
@@ -15,26 +21,26 @@ export type CandleData = {
1521
};
1622

1723
export type TrailingAvgData = {
18-
t: number;
19-
u: string;
20-
f: string;
24+
t: number; // timestamp
25+
u: string; // used
26+
f: string; // fee
2127
};
2228

2329
export type MarketPriceData = {
24-
v: string;
25-
t: number;
26-
e: number;
30+
v: string; // value
31+
t: number; // timestamp
32+
e: number; // end timestamp
2733
};
2834

2935
export type CandleMetadata = {
30-
u: string;
31-
f: string;
32-
st: number;
33-
et: number;
36+
u: string; // used
37+
f: string; // fee
38+
st: number; // start timestamp
39+
et: number; // end timestamp
3440
};
3541

3642
export type IndexStore = {
37-
data: ReducedCandleData[];
43+
data: (ReducedCandleData | ReducedIndexData)[];
3844
metadata: CandleMetadata[];
3945
trailingAvgData: TrailingAvgData[];
4046
};

packages/app/src/lib/hooks/useResources.ts

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface Market {
2121
name: string;
2222
vaultAddress: string;
2323
isYin: boolean;
24+
isCumulative: boolean;
2425
epochs: Epoch[];
2526
}
2627

@@ -72,6 +73,7 @@ const RESOURCES_QUERY = gql`
7273
id
7374
address
7475
isYin
76+
isCumulative
7577
vaultAddress
7678
chainId
7779
epochs {

0 commit comments

Comments
 (0)