Skip to content

Commit

Permalink
feat: add bot state
Browse files Browse the repository at this point in the history
  • Loading branch information
bludnic committed May 21, 2024
1 parent 6581631 commit ead5f44
Show file tree
Hide file tree
Showing 19 changed files with 110 additions and 24 deletions.
7 changes: 4 additions & 3 deletions packages/backtesting/src/backtesting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,14 @@ export class Backtesting<T extends IBotConfiguration<T>> {
console.table(fulfilledTable(this.store.getSmartTrades()));
}

const botState = {};
if (index === 0) {
await this.processor.start();
await this.processor.start(botState);
} else if (index === candlesticks.length - 1) {
// last candle
await this.processor.stop();
await this.processor.stop(botState);
} else {
await this.processor.process({
await this.processor.process(botState, {
candle,
candles: candlesticks.slice(0, index + 1),
});
Expand Down
10 changes: 7 additions & 3 deletions packages/bot-processor/src/strategy-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { BotControl } from "./bot-control";
import { effectRunnerMap } from "./effect-runner";
import { isEffect } from "./effects";
import type {
BotState,
BotTemplate,
IBotConfiguration,
IBotControl,
Expand All @@ -20,34 +21,37 @@ export class StrategyRunner<T extends IBotConfiguration> {
private botTemplate: BotTemplate<T>,
) {}

async start() {
async start(state: BotState) {
const context = createContext(
this.control,
this.botConfig,
this.exchange,
"start",
state,
);

await this.runTemplate(context);
}

async stop() {
async stop(state: BotState) {
const context = createContext(
this.control,
this.botConfig,
this.exchange,
"stop",
state,
);

await this.runTemplate(context);
}

async process(market?: MarketData) {
async process(state: BotState, market?: MarketData) {
const context = createContext(
this.control,
this.botConfig,
this.exchange,
"process",
state,
market,
);

Expand Down
5 changes: 5 additions & 0 deletions packages/bot-processor/src/types/bot/bot-context.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { IExchange } from "@opentrader/exchanges";
import type { MarketData } from "../market";
import type { IBotControl } from "./bot-control.interface";
import type { IBotConfiguration } from "./bot-configuration.interface";
import type { BotState } from "./bot.state";

export type TBotContext<T extends IBotConfiguration> = {
/**
Expand All @@ -16,6 +17,10 @@ export type TBotContext<T extends IBotConfiguration> = {
* Bot configuration
*/
config: T;
/**
* Bot's state
*/
state: BotState;
/**
* Event
*/
Expand Down
1 change: 1 addition & 0 deletions packages/bot-processor/src/types/bot/bot.state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type BotState = Record<string, any>;
1 change: 1 addition & 0 deletions packages/bot-processor/src/types/bot/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./bot-configuration.interface";
export * from "./bot-control.interface";
export * from "./bot-template.type";
export * from "./bot-context.type";
export * from "./bot.state";
3 changes: 3 additions & 0 deletions packages/bot-processor/src/utils/createContext.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { IExchange } from "@opentrader/exchanges";
import type {
BotState,
IBotConfiguration,
IBotControl,
MarketData,
Expand All @@ -11,6 +12,7 @@ export function createContext<T extends IBotConfiguration>(
config: T,
exchange: IExchange,
command: "start" | "stop" | "process", // @todo add type in file
state: BotState,
market: MarketData = {
candles: [],
},
Expand All @@ -23,6 +25,7 @@ export function createContext<T extends IBotConfiguration>(
onStart: command === "start",
onStop: command === "stop",
onProcess: command === "process",
state,
market,
};
}
1 change: 1 addition & 0 deletions packages/bot-templates/src/templates/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from "./trade";
export * from "./debug";
export * from "./candle";
export * from "./rsi";
export * from "./state";
26 changes: 26 additions & 0 deletions packages/bot-templates/src/templates/test/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { TBotContext } from "@opentrader/bot-processor";
import { logger } from "@opentrader/logger";

export function* testState(ctx: TBotContext<any>) {
const { config: bot, onStart, onStop } = ctx;

if (onStart) {
logger.info(ctx.state, `[TestState] Bot started`);

return;
}
if (onStop) {
logger.info(ctx.state, `[TestState] Bot stopped`);
return;
}

if (ctx.state.counter === undefined) {
ctx.state.counter = 0;
}

ctx.state.counter += 1;

logger.info(ctx.state, `[TestState] State is`);
}

testState.displayName = "Test State";
1 change: 1 addition & 0 deletions packages/cli/src/api/run-trading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ async function createOrUpdateBot<T = any>(
baseCurrency,
quoteCurrency,
settings: botConfig.settings as object,
state: {}, // resets bot state
exchangeAccount: {
connect: {
id: exchangeAccount.id,
Expand Down
23 changes: 15 additions & 8 deletions packages/db/src/extension/models/custom-bot.model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Prisma, PrismaClient } from "@prisma/client";
import type { TBotSettings } from "../../types";
import type { TBotSettings, TBotState } from "../../types";
import { ZBotSettings } from "../../types";

export const customBotModel = (prisma: PrismaClient) => ({
Expand All @@ -16,11 +16,12 @@ export const customBotModel = (prisma: PrismaClient) => ({
if (!bot) return null;

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TBotSettings,
state: bot.state as unknown as TBotState,
};
},
async findUnique<T extends Prisma.BotFindUniqueArgs>(
Expand All @@ -36,11 +37,12 @@ export const customBotModel = (prisma: PrismaClient) => ({
if (!bot) return null;

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TBotSettings,
state: bot.state as unknown as TBotState,
};
},
async findUniqueOrThrow<T extends Prisma.BotFindUniqueOrThrowArgs>(
Expand All @@ -54,11 +56,12 @@ export const customBotModel = (prisma: PrismaClient) => ({
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TBotSettings,
state: bot.state as unknown as TBotState,
};
},
async findFirstOrThrow<T extends Prisma.BotFindFirstOrThrowArgs>(
Expand All @@ -72,11 +75,12 @@ export const customBotModel = (prisma: PrismaClient) => ({
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TBotSettings,
state: bot.state as unknown as TBotState,
};
},
async findMany<T extends Prisma.BotFindManyArgs>(
Expand All @@ -91,11 +95,12 @@ export const customBotModel = (prisma: PrismaClient) => ({

return bots.map((bot) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TBotSettings,
state: bot.state as unknown as TBotState,
};
});
},
Expand All @@ -114,11 +119,12 @@ export const customBotModel = (prisma: PrismaClient) => ({
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TBotSettings,
state: bot.state as unknown as TBotState,
};
},
async update<T extends Prisma.BotUpdateArgs>(
Expand All @@ -139,11 +145,12 @@ export const customBotModel = (prisma: PrismaClient) => ({
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TBotSettings,
state: bot.state as unknown as TBotState,
};
},
async setProcessing(value: boolean, botId: number) {
Expand Down
19 changes: 13 additions & 6 deletions packages/db/src/extension/models/grid-bot.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Prisma, PrismaClient } from "@prisma/client";
import type { TBotState } from "../../types";
import type { TGridBotSettings } from "../../types/grid-bot";
import { ZGridBotSettings } from "../../types/grid-bot";

Expand All @@ -17,11 +18,12 @@ export const gridBotModel = (prisma: PrismaClient) => ({
if (!bot) return null;

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TGridBotSettings,
state: bot.state as unknown as TBotState,
};
},
async findUniqueOrThrow<T extends Prisma.BotFindUniqueOrThrowArgs>(
Expand All @@ -36,11 +38,12 @@ export const gridBotModel = (prisma: PrismaClient) => ({
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TGridBotSettings,
state: bot.state as unknown as TBotState,
};
},
async findFirstOrThrow<T extends Prisma.BotFindFirstOrThrowArgs>(
Expand All @@ -55,11 +58,12 @@ export const gridBotModel = (prisma: PrismaClient) => ({
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TGridBotSettings,
state: bot.state as unknown as TBotState,
};
},
async findMany<T extends Prisma.BotFindManyArgs>(
Expand All @@ -75,11 +79,12 @@ export const gridBotModel = (prisma: PrismaClient) => ({

return bots.map((bot) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TGridBotSettings,
state: bot.state as unknown as TBotState,
};
});
},
Expand All @@ -99,11 +104,12 @@ export const gridBotModel = (prisma: PrismaClient) => ({
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TGridBotSettings,
state: bot.state as unknown as TBotState,
};
},
async update<T extends Prisma.BotUpdateArgs>(
Expand All @@ -125,11 +131,12 @@ export const gridBotModel = (prisma: PrismaClient) => ({
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars -- required to destruct
const { settings, ...rest } = bot;
const { settings, state, ...rest } = bot;

return {
...rest,
settings: bot.settings as unknown as TGridBotSettings,
state: bot.state as unknown as TBotState,
};
},
});
5 changes: 5 additions & 0 deletions packages/db/src/types/bot/bot-state.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { z } from "zod";

export const ZBotState = z.record(z.any());

export type TBotState = z.infer<typeof ZBotState>;
2 changes: 2 additions & 0 deletions packages/db/src/types/bot/bot.schema.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { zt } from "@opentrader/prisma";
import type { z } from "zod";
import { ZBotSettings } from "./bot-settings.schema";
import { ZBotState } from "./bot-state.schema";

export const ZBot = zt.BotSchema.extend({
settings: ZBotSettings,
state: ZBotState,
});

export type TBot = z.infer<typeof ZBot>;
1 change: 1 addition & 0 deletions packages/db/src/types/bot/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./bot-settings.schema";
export * from "./bot.schema";
export * from "./bot-state.schema";
2 changes: 2 additions & 0 deletions packages/db/src/types/grid-bot/grid-bot.schema.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { zt } from "@opentrader/prisma";
import type { z } from "zod";
import { ZGridBotSettings } from "./grid-bot-settings.schema";
import { ZBotState } from "../bot/bot-state.schema";

export const ZGridBot = zt.BotSchema.extend({
settings: ZGridBotSettings,
state: ZBotState,
});

export type TGridBot = z.infer<typeof ZGridBot>;
Loading

0 comments on commit ead5f44

Please sign in to comment.