Skip to content
This repository was archived by the owner on Mar 14, 2024. It is now read-only.

Commit

Permalink
Fix prevPrice logic (#5)
Browse files Browse the repository at this point in the history
* Fix prevPrice logic

* Add CI for build and test

* rename getPrevPrice to getLatestAvailablePrice

- Also add getLatestAvailablePriceWithinDuration

Co-authored-by: Jayant Krishnamurthy <jkrishnamurthy@jumptrading.com>
  • Loading branch information
ali-bahjati and Jayant Krishnamurthy authored Aug 16, 2022
1 parent 58421e4 commit 7fd8ae7
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 16 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Node.js CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run build
- run: npm run lint
- run: npm test
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/pyth-sdk-js",
"version": "0.1.0",
"version": "0.2.0",
"description": "Pyth Network SDK in JS",
"homepage": "https://pyth.network",
"main": "lib/index.js",
Expand Down
48 changes: 45 additions & 3 deletions src/__tests__/PriceFeed.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { Price, PriceFeed, PriceStatus } from "../index";

beforeAll(() => {
jest.useFakeTimers();
});

test("Parsing Price Feed works as expected", () => {
const data = {
conf: "1",
Expand Down Expand Up @@ -28,11 +32,17 @@ test("Parsing Price Feed works as expected", () => {
expect(priceFeed.publishTime).toBe(11);
expect(priceFeed.getCurrentPrice()).toStrictEqual(new Price("1", 4, "10"));
expect(priceFeed.getEmaPrice()).toStrictEqual(new Price("2", 4, "3"));
expect(priceFeed.getPrevPriceUnchecked()).toStrictEqual([
new Price("7", 4, "8"),
9,
expect(priceFeed.getLatestAvailablePriceUnchecked()).toStrictEqual([
new Price("1", 4, "10"),
11,
]);

jest.setSystemTime(20000);
expect(priceFeed.getLatestAvailablePriceWithinDuration(15)).toStrictEqual(
new Price("1", 4, "10")
);
expect(priceFeed.getLatestAvailablePriceWithinDuration(5)).toBeUndefined();

expect(priceFeed.toJson()).toStrictEqual(data);
});

Expand All @@ -57,3 +67,35 @@ test("getCurrentPrice returns undefined if status is not Trading", () => {
const priceFeed = PriceFeed.fromJson(data);
expect(priceFeed.getCurrentPrice()).toBeUndefined();
});

test("getLatestAvailablePrice returns prevPrice when status is not Trading", () => {
const data = {
conf: "1",
ema_conf: "2",
ema_price: "3",
expo: 4,
id: "abcdef0123456789",
max_num_publishers: 6,
num_publishers: 5,
prev_conf: "7",
prev_price: "8",
prev_publish_time: 9,
price: "10",
product_id: "0123456789abcdef",
publish_time: 11,
status: PriceStatus.Unknown,
};

const priceFeed = PriceFeed.fromJson(data);

expect(priceFeed.getLatestAvailablePriceUnchecked()).toStrictEqual([
new Price("7", 4, "8"),
9,
]);

jest.setSystemTime(20000);
expect(priceFeed.getLatestAvailablePriceWithinDuration(15)).toStrictEqual(
new Price("7", 4, "8")
);
expect(priceFeed.getLatestAvailablePriceWithinDuration(10)).toBeUndefined();
});
61 changes: 51 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Convert, PriceFeed as JsonPriceFeed } from "./schemas/PriceFeed";

export type UnixTimestamp = number;
export type DurationInSeconds = number;
export type HexString = string;

/**
Expand Down Expand Up @@ -190,9 +191,14 @@ export class PriceFeed {

/**
* Get the current price and confidence interval as fixed-point numbers of the form a * 10^e.
* This function returns the current best estimate of the price at the time that this `PriceFeed` was
* published (`publish_time`). This function returns `undefined` if the oracle was unable to determine
* the price at that time; this condition can happen for various reasons, such as certain markets only
* trading during certain times.
*
* @returns a struct containing the current price, confidence interval, and the exponent for
* both numbers. Returns `undefined` if price information is currently unavailable for any reason.
* @returns a struct containing the price and confidence interval as of `publish_time`, along with
* the exponent for both numbers. Returns `undefined` if price information is currently unavailable
* for any reason.
*/
getCurrentPrice(): Price | undefined {
if (this.status !== PriceStatus.Trading) {
Expand All @@ -216,20 +222,55 @@ export class PriceFeed {
}

/**
* Get the "unchecked" previous price with Trading status, along with the timestamp at which it was generated.
* Get the latest available price, along with the timestamp when it was generated.
* This function returns the same price as `getCurrentPrice` in the case where a price was available
* at the time this `PriceFeed` was published (`publish_time`). However, if a price was not available
* at that time, this function returns the price from the latest time at which the price was available.
* The returned price can be from arbitrarily far in the past; this function makes no guarantees that
* the returned price is recent or useful for any particular application.
*
* @returns a struct containing the previous price, confidence interval, and the exponent for
* both numbers along with the timestamp that the price was generated.
* Users of this function should check the returned timestamp to ensure that the returned price is
* sufficiently recent for their application. If you are considering using this function, it may be
* safer / easier to use either `getCurrentPrice` or `getLatestAvailablePriceWithinDuration`.
*
* WARNING:
* We make no guarantees about the unchecked price and confidence returned by
* this function: it could differ significantly from the current price.
* We strongly encourage you to use `get_current_price` instead.
* @returns a struct containing the latest available price, confidence interval, and the exponent for
* both numbers along with the timestamp when that price was generated.
*/
getPrevPriceUnchecked(): [Price, UnixTimestamp] {
getLatestAvailablePriceUnchecked(): [Price, UnixTimestamp] {
// If the price status is Trading then it's the latest price
// with the Trading status.
if (this.status === PriceStatus.Trading) {
return [new Price(this.conf, this.expo, this.price), this.publishTime];
}

return [
new Price(this.prevConf, this.expo, this.prevPrice),
this.prevPublishTime,
];
}

/**
* Get the latest price as long as it was updated within `duration` seconds of the current time.
* This function is a sanity-checked version of `getLatestAvailablePriceUnchecked` which is useful in
* applications that require a sufficiently-recent price. Returns `undefined` if the price wasn't
* updated sufficiently recently.
*
* @param duration return a price as long as it has been updated within this number of seconds
* @returns a struct containing the latest available price, confidence interval and the exponent for
* both numbers, or `undefined` if no price update occurred within `duration` seconds of the current time.
*/
getLatestAvailablePriceWithinDuration(duration: DurationInSeconds): Price | undefined {
const [price, timestamp] = this.getLatestAvailablePriceUnchecked();

const currentTime: UnixTimestamp = Math.floor(Date.now() / 1000);

// This checks the absolute difference as a sanity check
// for the cases that the system time is behind or price
// feed timestamp happen to be in the future (a bug).
if (Math.abs(currentTime - timestamp) > duration) {
return undefined;
}

return price;
}
}

0 comments on commit 7fd8ae7

Please sign in to comment.