Skip to content

Commit

Permalink
FOIL-256 Fix the different index prices
Browse files Browse the repository at this point in the history
  • Loading branch information
leomassazza committed Feb 13, 2025
1 parent a4a7d51 commit 77c43e4
Showing 1 changed file with 33 additions and 74 deletions.
107 changes: 33 additions & 74 deletions packages/api/src/graphql/resolvers/CandleResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,16 +163,15 @@ const getTrailingAveragePricesByInterval = (
};

const getIndexPricesByInterval = (
orderedPrices: ResourcePricePoint[],
orderedPrices: ResourcePricePoint[], // prices ordered by timestamp starting from the epoch start time
intervalSeconds: number,
startTimestamp: number,
endTimestamp: number,
lastKnownPrice?: string
endTimestamp: number
): CandleType[] => {
const candles: CandleType[] = [];

// If we have no prices and no reference price, return empty array
if (orderedPrices.length === 0 && !lastKnownPrice) return [];
if (orderedPrices.length === 0) return [];

// Normalize timestamps to interval boundaries
const normalizedStartTimestamp =
Expand All @@ -181,37 +180,28 @@ const getIndexPricesByInterval = (
Math.floor(endTimestamp / intervalSeconds) * intervalSeconds;

// Initialize lastClose with lastKnownPrice if available, otherwise use first price
let lastClose = lastKnownPrice || orderedPrices[0].value;
let lastClose = orderedPrices[0].value;

let endIdx = 0;
let lastEndIdx = 0; // always start from the first item in the orderedPrices array, since it starts from the epoch start time

let totalGasUsed: bigint = 0n;
let totalBaseFeesPaid: bigint = 0n;

// get the indexes for the start and end of the interval
let lastEndIdx = orderedPrices.findIndex(
(p) => p.timestamp >= normalizedStartTimestamp
);

for (
let timestamp = normalizedStartTimestamp;
timestamp <= normalizedEndTimestamp;
timestamp += intervalSeconds
) {
endIdx = orderedPrices.findIndex((p) => p.timestamp > timestamp); // notice is the next item, we need to correct it later

// if found and not previous endIdx, correct the +1 offset of the endIdx (since we found the next item)
if (endIdx != -1 && endIdx > lastEndIdx) {
endIdx--;
}

// If not found, use the last index of the orderedPrices array
if (endIdx == -1) {
endIdx = orderedPrices.length - 1;
endIdx = orderedPrices.length;
}

// Add to the sliding window trailing average the prices that are now in the interval
for (let i = lastEndIdx; i <= endIdx; i++) {
for (let i = lastEndIdx; i < endIdx; i++) {
totalGasUsed += BigInt(orderedPrices[i].used);
totalBaseFeesPaid += BigInt(orderedPrices[i].feePaid);
}
Expand All @@ -223,7 +213,7 @@ const getIndexPricesByInterval = (
lastClose = averagePrice.toString();
}

// Create candle with last known closing price (calculated in the loop or previous candle)
// Create candle with last known closing price (calculated or previous candle)
candles.push({
timestamp,
open: lastClose,
Expand All @@ -240,34 +230,32 @@ const getIndexPriceAtTime = (
orderedPrices: ResourcePricePoint[],
timestamp: number
): CandleType => {
let totalGasUsed: bigint = 0n;
let totalBaseFeesPaid: bigint = 0n;
let lastClose: string = '';

// Add to the sliding window trailing average the prices that are now in the interval
for (let i = 0; i < orderedPrices.length; i++) {
if (orderedPrices[i].timestamp <= timestamp) {
totalGasUsed += BigInt(orderedPrices[i].used);
totalBaseFeesPaid += BigInt(orderedPrices[i].feePaid);
}
}

let totalGasUsed: bigint = 0n;
let totalBaseFeesPaid: bigint = 0n;
let lastClose: string = '';

// Calculate the average price for the interval
if (totalGasUsed > 0n) {
const averagePrice: bigint = totalBaseFeesPaid / totalGasUsed;
lastClose = averagePrice.toString();
// Add to the sliding window trailing average the prices that are now in the interval
for (let i = 0; i < orderedPrices.length; i++) {
if (orderedPrices[i].timestamp <= timestamp) {
totalGasUsed += BigInt(orderedPrices[i].used);
totalBaseFeesPaid += BigInt(orderedPrices[i].feePaid);
}
}

return {
timestamp,
open: lastClose,
high: lastClose,
low: lastClose,
close: lastClose,
};
// Calculate the average price for the interval
if (totalGasUsed > 0n) {
const averagePrice: bigint = totalBaseFeesPaid / totalGasUsed;
lastClose = averagePrice.toString();
}

}
return {
timestamp,
open: lastClose,
high: lastClose,
low: lastClose,
close: lastClose,
};
};

@Resolver()
export class CandleResolver {
Expand Down Expand Up @@ -430,37 +418,10 @@ export class CandleResolver {
// Ensure we don't query prices before epoch start time
const effectiveFromTime = Math.max(from, Number(epoch.startTimestamp));

// Only get last price before if it's after epoch start time
// First get the most recent price before the trailingFrom timestamp
const lastPriceBefore =
effectiveFromTime > Number(epoch.startTimestamp)
? await dataSource
.getRepository(ResourcePrice)
.createQueryBuilder('price')
.where('price.resourceId = :resourceId', {
resourceId: resource.id,
})
.andWhere('price.timestamp < :from', { from: effectiveFromTime })
.andWhere('price.timestamp >= :startTime', {
startTime: epoch.startTimestamp,
})
.orderBy('price.timestamp', 'DESC')
.take(1)
.getOne()
: null;

const lastKnownPrice = lastPriceBefore
? lastPriceBefore?.feePaid && lastPriceBefore?.used
? (
BigInt(lastPriceBefore?.feePaid) / BigInt(lastPriceBefore?.used)
).toString()
: lastPriceBefore?.value
: undefined;

const pricesInRange = await dataSource.getRepository(ResourcePrice).find({
where: {
resource: { id: resource.id },
timestamp: Between(effectiveFromTime, to),
timestamp: Between(Number(epoch.startTimestamp), to),
},
order: { timestamp: 'ASC' },
});
Expand All @@ -474,8 +435,7 @@ export class CandleResolver {
})),
interval,
effectiveFromTime,
to,
lastKnownPrice
to
);
} catch (error) {
console.error('Error fetching index candles:', error);
Expand Down Expand Up @@ -636,5 +596,4 @@ export class CandleResolver {
throw new Error('Failed to fetch market candles');
}
}

}
}

0 comments on commit 77c43e4

Please sign in to comment.