Skip to content

Commit

Permalink
Merge pull request #14 from debut-js/alpha
Browse files Browse the repository at this point in the history
Alpha Release with Futures support & fixes
  • Loading branch information
BusinessDuck authored Aug 27, 2021
2 parents 920c0c6 + 3c8078a commit ead8a54
Show file tree
Hide file tree
Showing 12 changed files with 6,490 additions and 483 deletions.
6,539 changes: 6,196 additions & 343 deletions package-lock.json

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@debut/community-core",
"version": "2.4.6",
"version": "2.4.7-beta.2",
"publishConfig": {
"access": "public"
},
Expand All @@ -26,36 +26,36 @@
"genetic": "lib/cli/genetic.js"
},
"dependencies": {
"@debut/plugin-utils": "^1.0.14",
"@master-chief/alpaca": "^6.2.4",
"@debut/plugin-utils": "^1.0.17",
"@master-chief/alpaca": "^6.2.6",
"@tinkoff/invest-openapi-js-sdk": "^1.5.0",
"async-genetic": "^1.4.2",
"binance-api-node": "0.10.49",
"binance-api-node": "0.11.12",
"cli-progress": "^3.9.0",
"node-fetch": "^2.6.1",
"@types/ws": "^7.4.7"
},
"devDependencies": {
"@debut/types": "^1.0.24",
"@debut/types": "^1.1.0",
"@types/benchmark": "^2.1.1",
"@types/cli-progress": "^3.9.2",
"@types/jest": "^26.0.24",
"@types/node": "^16.4.1",
"@typescript-eslint/eslint-plugin": "^4.28.4",
"@typescript-eslint/parser": "^4.28.4",
"@types/jest": "^27.0.1",
"@types/node": "^16.7.2",
"@typescript-eslint/eslint-plugin": "^4.29.3",
"@typescript-eslint/parser": "^4.29.3",
"benchmark": "^2.1.4",
"eslint": "^7.31.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-prettier": "^3.4.1",
"git-format-staged": "^2.1.2",
"husky": "4.3.8",
"jest": "^27.0.6",
"prettier": "^2.3.2",
"rollup": "^2.53.3",
"rollup": "^2.56.3",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.30.0",
"ts-jest": "^27.0.4",
"typescript": "^4.3.5"
"ts-jest": "^27.0.5",
"typescript": "^4.4.2"
},
"husky": {
"hooks": {
Expand Down
26 changes: 17 additions & 9 deletions src/cli/tester-cli.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TesterTransport } from './tester/tester-transport';
import { getHistory } from './tester/history';
import { cli } from '@debut/plugin-utils';
import { DebutMeta, DebutOptions, WorkingEnv } from '@debut/types';
import { DebutMeta, DebutOptions, InstrumentType, WorkingEnv } from '@debut/types';

type Params = {
bot: string;
Expand All @@ -27,24 +27,32 @@ const schema: cli.BotData | null = cli.getBotData(bot);
test(cfg, meta);
})();

async function test(cfg: DebutOptions, meta: DebutMeta) {
async function test(opts: DebutOptions, meta: DebutMeta) {
try {
const transport = new TesterTransport({ ohlc, comission: cfg.fee, broker: cfg.broker, ticker: cfg.ticker });
const bot = await meta.create(transport, cfg, WorkingEnv.tester);
const transport = new TesterTransport({ ohlc, comission: opts.fee, broker: opts.broker, ticker: opts.ticker });
const bot = await meta.create(transport, opts, WorkingEnv.tester);
// const logger = new TesterLogger(transport);

if (!cfg) {
if (!opts) {
process.stdout.write('Genetic CLI error: Put config in bot cfgs.ts file');
}

const { broker = 'tinkoff', ticker, interval } = cfg;
let ticks = await getHistory({ broker, ticker, interval, days, gapDays: gap });
const { broker = 'tinkoff', ticker, interval, instrumentType } = opts;

let ticks = await getHistory({
broker,
ticker,
interval,
days,
gapDays: gap,
instrumentType,
});

if (meta.ticksFilter) {
ticks = ticks.filter(meta.ticksFilter(cfg));
ticks = ticks.filter(meta.ticksFilter(opts));
}

console.log('\n---- Tinkoff [' + cfg.ticker + '] ----\n');
console.log('\n---- Tinkoff [' + opts.ticker + '] ----\n');
console.log('Tested in ', ticks.length, ' candles...');
transport.setTicks(ticks);
await bot.start();
Expand Down
5 changes: 4 additions & 1 deletion src/cli/tester/genetic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
SchemaDescriptor,
TestingPhase,
DebutCore,
InstrumentType,
} from '@debut/types';
import { Genetic, GeneticOptions, Phenotype, Select } from 'async-genetic';
import { getHistory } from './history';
Expand Down Expand Up @@ -64,14 +65,16 @@ export class GeneticWrapper {
ticker: opts.ticker,
});

const { broker = 'tinkoff', ticker, interval } = opts;
const { broker = 'tinkoff', ticker, interval, instrumentType } = opts;
const { days, gapDays } = this.options;

let ticks = await getHistory({
broker,
ticker,
interval,
days,
gapDays,
instrumentType,
});

if (this.options.ticksFilter) {
Expand Down
47 changes: 33 additions & 14 deletions src/cli/tester/history-providers/binance.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
import { TimeFrame, Candle } from '@debut/types';
import { TimeFrame, Candle, InstrumentType } from '@debut/types';
import { convertTimeFrame } from '../../../transports/binance';
import { DebutError, ErrorEnvironment } from '../../../modules/error';

export async function requestBinance(from: number, to: number, ticker: string, interval: TimeFrame): Promise<Candle[]> {
const frameMin = convertTimeFrame(interval);
export function createRequestBinance(instrumentType: InstrumentType) {
let endpoint = 'api.binance.com';
let apiName = 'api';
let apiVersion = 'v3';

const middleDay = from + 12 * 60 * 60 * 1000 - 1000;
const urlPart1 = `https://api.binance.com/api/v1/klines?symbol=${ticker}&interval=${frameMin}&startTime=${from}&endTime=${middleDay}&limit=720`;
const urlPart2 = `https://api.binance.com/api/v1/klines?symbol=${ticker}&interval=${frameMin}&startTime=${middleDay}&endTime=${to}&limit=720`;
const req1: Promise<[]> = fetch(urlPart1).then((res) => res.json());
const req2: Promise<[]> = fetch(urlPart2).then((res) => res.json());
const candles1 = (await req1) || [];
const candles2 = (await req2) || [];

if (!Array.isArray(candles2) || !Array.isArray(candles1)) {
throw candles1['msg'] || candles2['msg'];
if (instrumentType === 'FUTURES') {
endpoint = 'fapi.binance.com';
apiName = 'fapi';
apiVersion = 'v1';
}

return convertBinanceTicks([...candles1, ...candles2]);
const apiBase = `https://${endpoint}/${apiName}/${apiVersion}`;

return async function requestBinance(
from: number,
to: number,
ticker: string,
interval: TimeFrame,
): Promise<Candle[]> {
const frameMin = convertTimeFrame(interval);
const middleDay = from + 12 * 60 * 60 * 1000 - 1000;
const urlPart1 = `${apiBase}/klines?symbol=${ticker}&interval=${frameMin}&startTime=${from}&endTime=${middleDay}&limit=720`;
const urlPart2 = `${apiBase}/klines?symbol=${ticker}&interval=${frameMin}&startTime=${middleDay}&endTime=${to}&limit=720`;
const req1: Promise<[]> = fetch(urlPart1).then((res) => res.json());
const req2: Promise<[]> = middleDay < to ? fetch(urlPart2).then((res) => res.json()) : Promise.resolve([]);
const candles1 = (await req1) || [];
const candles2 = (await req2) || [];

if (!Array.isArray(candles2) || !Array.isArray(candles1)) {
throw new DebutError(ErrorEnvironment.History, candles1['msg'] || candles2['msg']);
}

return convertBinanceTicks([...candles1, ...candles2]);
};
}

function convertBinanceTicks(data: []) {
Expand Down
15 changes: 9 additions & 6 deletions src/cli/tester/history.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { date, file, promise } from '@debut/plugin-utils';
import { Candle, TimeFrame } from '@debut/types';
import { Candle, InstrumentType, TimeFrame } from '@debut/types';
import { SingleBar, Presets } from 'cli-progress';
import { DebutError, ErrorEnvironment } from '../../modules/error';
import { requestAlpaca } from './history-providers/alpaca';
import { requestBinance } from './history-providers/binance';
import { createRequestBinance } from './history-providers/binance';
import { requestTinkoff } from './history-providers/tinkoff';

const DAY = 86400000;
export type RequestFn = (from: number, to: number, ticker: string, interval: TimeFrame) => Promise<Candle[]>;
export interface HistoryOptions {
broker: 'tinkoff' | 'binance' | 'alpaca';
ticker: string;
instrumentType: InstrumentType;
days: number;
interval: TimeFrame;
gapDays: number;
Expand All @@ -28,7 +29,7 @@ export async function getHistory(options: HistoryOptions): Promise<Candle[]> {
requestFn = requestTinkoff;
break;
case 'binance':
requestFn = requestBinance;
requestFn = createRequestBinance(options.instrumentType);
break;
case 'alpaca':
requestFn = requestAlpaca;
Expand All @@ -45,7 +46,7 @@ export async function getHistory(options: HistoryOptions): Promise<Candle[]> {
* History validation is inside. If something is broken you will see error.
*/
async function createHistory(options: HistoryOptions, requestFn: RequestFn) {
const { ticker, days, interval, gapDays, broker, noProgress = false } = options;
const { ticker, days, interval, gapDays, broker, noProgress = false, instrumentType } = options;
const reqs = [];
const now = new Date();
const stamp = gapDays ? roundDay(now.getTime()) : now.getTime();
Expand All @@ -70,7 +71,7 @@ async function createHistory(options: HistoryOptions, requestFn: RequestFn) {
chunkStart = from;
}

reqs.push(createRequest(broker, ticker, interval, from, to, requestFn));
reqs.push(createRequest(broker, ticker, interval, from, to, instrumentType, requestFn));

if (reqs.length === 50 || to >= end) {
const data = await collectCandles(reqs);
Expand Down Expand Up @@ -113,11 +114,13 @@ async function createRequest(
interval: TimeFrame,
from: number,
to: number,
instrumentType: InstrumentType,
requestFn: RequestFn,
) {
const validFrom = from / 100000;
const validTo = to / 100000;
const path = `history/${broker}/${ticker}/${interval}/${validFrom}-${validTo}.txt`;
const subfolder = instrumentType === 'FUTURES' ? '/futures/' : '';
const path = `history/${broker}/${subfolder}${ticker}/${interval}/${validFrom}-${validTo}.txt`;
const historyFile = file.readFile(path);

if (validFrom !== ~~validFrom) {
Expand Down
24 changes: 20 additions & 4 deletions src/cli/tester/tester-transport.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { promise, orders, math } from '@debut/plugin-utils';
import { BaseTransport, TickHandler, Instrument, ExecutedOrder, Candle, TestingPhase } from '@debut/types';
import {
BaseTransport,
TickHandler,
Instrument,
ExecutedOrder,
Candle,
TestingPhase,
DebutOptions,
PendingOrder,
} from '@debut/types';
import { generateOHLC } from './history';
import { PendingOrder } from '@debut/types';

type TesterTransportOptions = {
ticker: string;
Expand Down Expand Up @@ -36,7 +44,9 @@ export class TesterTransport implements BaseTransport {
};
}

public async getInstrument() {
public async getInstrument(opts: DebutOptions) {
const instrumentId = this.getInstrumentId(opts);

if (!this.tickPhases.main.length) {
throw new Error('transport is not ready, set ticks before bot.start() call');
}
Expand All @@ -63,6 +73,8 @@ export class TesterTransport implements BaseTransport {
lotPrecision: 10,
lot: 1,
currency: 'USD',
id: instrumentId,
type: opts.instrumentType,
} as Instrument;
}

Expand Down Expand Up @@ -117,7 +129,7 @@ export class TesterTransport implements BaseTransport {
this.onPhase = onPhase;
}

public subscribeToTick(ticker: string, handler: TickHandler) {
public subscribeToTick(opts: DebutOptions, handler: TickHandler) {
this.handlers.push(handler);

return Promise.resolve(() => {
Expand Down Expand Up @@ -178,4 +190,8 @@ export class TesterTransport implements BaseTransport {

this.resolve();
}

private getInstrumentId(opts: DebutOptions) {
return `${opts.ticker}:${opts.instrumentType}`;
}
}
Loading

0 comments on commit ead8a54

Please sign in to comment.