Skip to content
Snippets Groups Projects
Verified Commit 3748a153 authored by Mateusz Tyszczak's avatar Mateusz Tyszczak :scroll:
Browse files

Add feed price filters and providers

parent fd040baf
No related branches found
No related tags found
1 merge request!25Add missing filters and providers
...@@ -6,6 +6,13 @@ export interface IFeedPriceData { ...@@ -6,6 +6,13 @@ export interface IFeedPriceData {
marketMedianHistory: price; marketMedianHistory: price;
currentMinHistory: price; currentMinHistory: price;
currentMaxHistory: price; currentMaxHistory: price;
/**
* Note: This is a timestamp of the last feed price retrieval, not the actual feed price interval timestamp.
*/
lastFeedPriceRetrievalTimestamp: Date;
/**
* Contains feed price history updated every hour from the latest to the oldest.
*/
priceHistory: Iterable<price>; priceHistory: Iterable<price>;
} }
......
...@@ -29,7 +29,8 @@ export class FeedPriceCollector extends CollectorBase { ...@@ -29,7 +29,8 @@ export class FeedPriceCollector extends CollectorBase {
marketMedianHistory: feedHistoryData.market_median_history, marketMedianHistory: feedHistoryData.market_median_history,
currentMinHistory: feedHistoryData.current_min_history, currentMinHistory: feedHistoryData.current_min_history,
currentMaxHistory: feedHistoryData.current_max_history, currentMaxHistory: feedHistoryData.current_max_history,
priceHistory: feedHistoryData.price_history priceHistory: feedHistoryData.price_history.reverse(),
lastFeedPriceRetrievalTimestamp: new Date()
}; };
} }
......
import { price } from "@hiveio/wax";
import type { WorkerBee } from "../../bot";
import { FeedPriceClassifier } from "../classifiers";
import type { TRegisterEvaluationContext } from "../classifiers/collector-classifier-base";
import type { DataEvaluationContext } from "../factories/data-evaluation-context";
import { FilterBase } from "./filter-base";
export class FeedPriceChangeFilter extends FilterBase {
public constructor(
worker: WorkerBee,
private readonly feedPriceChangePercentMin: number
) {
super(worker);
}
public usedContexts(): Array<TRegisterEvaluationContext> {
return [
FeedPriceClassifier
];
}
private previousUpdateTimestamp: Date | undefined;
public async match(data: DataEvaluationContext): Promise<boolean> {
const { priceHistory, lastFeedPriceRetrievalTimestamp } = await data.get(FeedPriceClassifier);
if (this.previousUpdateTimestamp && this.previousUpdateTimestamp > lastFeedPriceRetrievalTimestamp)
return false;
const history: Array<Exclude<price, undefined>> = Array.from(priceHistory);
if (history.length < 2)
return false;
const price1 = BigInt(history[0].base!.amount) / BigInt(history[0].quote!.amount);
const price2 = BigInt(history[1].base!.amount) / BigInt(history[1].quote!.amount);
let percentChange = (price1 - price2) * BigInt(100) / price2;
if (percentChange < 0)
percentChange = -percentChange;
this.previousUpdateTimestamp = lastFeedPriceRetrievalTimestamp;
return Number(percentChange.toString()) >= this.feedPriceChangePercentMin;
}
}
import type { WorkerBee } from "../../bot";
import { FeedPriceClassifier } from "../classifiers";
import type { TRegisterEvaluationContext } from "../classifiers/collector-classifier-base";
import type { DataEvaluationContext } from "../factories/data-evaluation-context";
import { FilterBase } from "./filter-base";
export class FeedPriceNoChangeFilter extends FilterBase {
/**
* @param worker @internal
* @param feedPriceNoChangeIntervals In standard configuration - one interval is one hour, so the default 24 intervals is one day.
*/
public constructor(
worker: WorkerBee,
private readonly feedPriceNoChangeIntervals: number = 24
) {
super(worker);
}
public usedContexts(): Array<TRegisterEvaluationContext> {
return [
FeedPriceClassifier
];
}
private previousUpdateTimestamp: Date | undefined;
public async match(data: DataEvaluationContext): Promise<boolean> {
const { priceHistory, lastFeedPriceRetrievalTimestamp } = await data.get(FeedPriceClassifier);
if (this.previousUpdateTimestamp && this.previousUpdateTimestamp > lastFeedPriceRetrievalTimestamp)
return false;
let previousPrice: bigint | undefined;
let index = 0;
let priceChanged = false;
for(const entry of priceHistory) {
const price = BigInt(entry.base!.amount) / BigInt(entry.quote!.amount);
if (previousPrice === undefined) {
previousPrice = price;
continue;
}
if (previousPrice !== price) {
priceChanged = true;
break;
}
++index;
if (index >= this.feedPriceNoChangeIntervals)
break;
}
return priceChanged;
}
}
import { price } from "@hiveio/wax";
import { WorkerBeeIterable } from "src/types/iterator";
import { FeedPriceClassifier } from "../classifiers";
import { TRegisterEvaluationContext } from "../classifiers/collector-classifier-base";
import { DataEvaluationContext } from "../factories/data-evaluation-context";
import { ProviderBase } from "./provider-base";
export interface IFeedPriceData {
priceHistory: WorkerBeeIterable<price>;
currentMinHistory: price;
currentMaxHistory: price;
currentMedianHistory: price;
}
export interface IFeedPriceProviderData {
feedPrice: IFeedPriceData;
};
export class FeedPriceProvider extends ProviderBase {
public usedContexts(): Array<TRegisterEvaluationContext> {
return [
FeedPriceClassifier
]
}
public async provide(data: DataEvaluationContext): Promise<IFeedPriceProviderData> {
const { currentMedianHistory, currentMinHistory, currentMaxHistory, priceHistory } = await data.get(FeedPriceClassifier);
return {
feedPrice: {
currentMedianHistory,
currentMinHistory,
currentMaxHistory,
priceHistory: new WorkerBeeIterable(priceHistory)
}
};
}
}
...@@ -9,6 +9,8 @@ import { BlockNumberFilter } from "./chain-observers/filters/block-filter"; ...@@ -9,6 +9,8 @@ import { BlockNumberFilter } from "./chain-observers/filters/block-filter";
import { LogicalAndFilter, LogicalOrFilter } from "./chain-observers/filters/composite-filter"; import { LogicalAndFilter, LogicalOrFilter } from "./chain-observers/filters/composite-filter";
import { CustomOperationFilter } from "./chain-observers/filters/custom-operation-filter"; import { CustomOperationFilter } from "./chain-observers/filters/custom-operation-filter";
import { ExchangeTransferFilter } from "./chain-observers/filters/exchange-transfer-filter"; import { ExchangeTransferFilter } from "./chain-observers/filters/exchange-transfer-filter";
import { FeedPriceChangeFilter } from "./chain-observers/filters/feed-price-change-percent-filter";
import { FeedPriceNoChangeFilter } from "./chain-observers/filters/feed-price-no-change-filter";
import type { FilterBase } from "./chain-observers/filters/filter-base"; import type { FilterBase } from "./chain-observers/filters/filter-base";
import { FollowFilter } from "./chain-observers/filters/follow-filter"; import { FollowFilter } from "./chain-observers/filters/follow-filter";
import { ImpactedAccountFilter } from "./chain-observers/filters/impacted-account-filter"; import { ImpactedAccountFilter } from "./chain-observers/filters/impacted-account-filter";
...@@ -23,6 +25,7 @@ import { AccountProvider } from "./chain-observers/providers/account-provider"; ...@@ -23,6 +25,7 @@ import { AccountProvider } from "./chain-observers/providers/account-provider";
import { BlockHeaderProvider } from "./chain-observers/providers/block-header-provider"; import { BlockHeaderProvider } from "./chain-observers/providers/block-header-provider";
import { BlockProvider } from "./chain-observers/providers/block-provider"; import { BlockProvider } from "./chain-observers/providers/block-provider";
import { ExchangeTransferProvider } from "./chain-observers/providers/exchange-transfer-provider"; import { ExchangeTransferProvider } from "./chain-observers/providers/exchange-transfer-provider";
import { FeedPriceProvider } from "./chain-observers/providers/feed-price-provider";
import { MentionedAccountProvider } from "./chain-observers/providers/mention-provider"; import { MentionedAccountProvider } from "./chain-observers/providers/mention-provider";
import { ProviderBase } from "./chain-observers/providers/provider-base"; import { ProviderBase } from "./chain-observers/providers/provider-base";
import { RcAccountProvider } from "./chain-observers/providers/rc-account-provider"; import { RcAccountProvider } from "./chain-observers/providers/rc-account-provider";
...@@ -134,6 +137,24 @@ export class QueenBee<TPreviousSubscriberData extends object = {}> { ...@@ -134,6 +137,24 @@ export class QueenBee<TPreviousSubscriberData extends object = {}> {
return this; return this;
} }
public onFeedPriceChange(percent: number): QueenBee<TPreviousSubscriberData> {
this.operands.push(new FeedPriceChangeFilter(this.worker, percent));
return this;
}
public onFeedPriceNoChange(lastHoursCount: number = 24): QueenBee<TPreviousSubscriberData> {
this.operands.push(new FeedPriceNoChangeFilter(this.worker, lastHoursCount));
return this;
}
public provideFeedPriceData(): QueenBee<TPreviousSubscriberData & Awaited<ReturnType<FeedPriceProvider["provide"]>>> {
this.providers.push(new FeedPriceProvider());
return this;
}
public onReblog(reblogger: TAccountName): QueenBee<TPreviousSubscriberData> { public onReblog(reblogger: TAccountName): QueenBee<TPreviousSubscriberData> {
this.operands.push(new ReblogFilter(this.worker, reblogger)); this.operands.push(new ReblogFilter(this.worker, reblogger));
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment