-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Save backtest history in sqlite. (#60)
* Save backtest history in sqlite. Get backtest history by strategyId. Get backtest history strategy details by id. Set backtest strategy as favorite. * Sqlite Db connection error check added. symbol column datatype size increase. * Typo fix. * Unit tests added for Sqlite DB and Backtest DAO functions. * Save bt result to db. Replaced meta with executionId. Added function to delete bt. * BtData: parse btResult * send bt id as second argument in responce array * Added endpoint to delete all bts by strategy ID. * send bt full data on single request * normalize bt history response data * send message on success bt saving * Return error if backtest execution fails. Changed saveBt callback to async call. Fixed unit test. * typo fix * Call sqlite connection method from server open method * log sqlite connection error --------- Co-authored-by: Dmytro Shcherbonos <dmytro.sh@code-care.pro>
- Loading branch information
1 parent
9aeaffb
commit 64e0a2a
Showing
12 changed files
with
407 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
'use strict' | ||
|
||
const { deleteAllBts } = require('../db/bt_dao') | ||
const send = require('../wss/send') | ||
|
||
module.exports = async (ds, ws, msg) => { | ||
const [, strategyId] = msg | ||
|
||
await deleteAllBts(strategyId) | ||
send(ws, ['data.bt.history.all.deleted', strategyId]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
'use strict' | ||
|
||
const { deleteBt } = require('../db/bt_dao') | ||
const send = require('../wss/send') | ||
|
||
module.exports = async (ds, ws, msg) => { | ||
const [, executionId] = msg | ||
|
||
await deleteBt(executionId) | ||
send(ws, ['data.bt.history.deleted', executionId]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
'use strict' | ||
|
||
const { getBtHistory } = require('../db/bt_dao') | ||
const send = require('../wss/send') | ||
|
||
module.exports = async (ds, ws, msg) => { | ||
const [, strategyId] = msg | ||
const btHistory = await getBtHistory(strategyId) | ||
|
||
send(ws, ['data.bt.history.list', strategyId, btHistory]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
'use strict' | ||
|
||
const { setBtFavorite } = require('../db/bt_dao') | ||
const send = require('../wss/send') | ||
|
||
module.exports = async (ds, ws, msg) => { | ||
const [, executionId, isFavorite] = msg | ||
|
||
await setBtFavorite(executionId, isFavorite) | ||
send(ws, ['data.bt.history.favorite', executionId, !!isFavorite]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
const sqliteDb = require('./sqlite_db') | ||
|
||
const saveBt = async (args, btResult) => { | ||
const [ | ||
exchange, strategyId, start, end, symbol, timeframe, | ||
includeCandles, includeTrades, candleSeed, sync = true, , executionId, | ||
{ capitalAllocation, stopLossPerc, maxDrawdownPerc } | ||
] = args | ||
|
||
const isFavorite = 0 | ||
const timestamp = Date.now() | ||
|
||
const query = 'insert into bt_history (exchange, strategyId, start, end, symbol, timeframe, includeCandles, includeTrades, candleSeed, sync, executionId, capitalAllocation, stopLossPerc, maxDrawdownPerc, isFavorite, timestamp, btResult) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)' | ||
const values = [ | ||
exchange, strategyId, start, end, symbol, timeframe, | ||
includeCandles, includeTrades, candleSeed, sync, executionId, | ||
capitalAllocation, stopLossPerc, maxDrawdownPerc, | ||
isFavorite, timestamp, JSON.stringify(btResult) | ||
] | ||
|
||
await sqliteDb.createData(query, values) | ||
|
||
const savedBt = { | ||
exchange, | ||
strategyId, | ||
start, | ||
end, | ||
symbol, | ||
timeframe, | ||
includeCandles, | ||
includeTrades, | ||
candleSeed, | ||
sync, | ||
executionId, | ||
capitalAllocation, | ||
stopLossPerc, | ||
maxDrawdownPerc, | ||
isFavorite: false, | ||
timestamp, | ||
btResult | ||
} | ||
|
||
return savedBt | ||
} | ||
|
||
const getBtHistory = async (strategyId) => { | ||
const query = 'SELECT * FROM bt_history where strategyId=?' | ||
const values = [strategyId] | ||
|
||
const btHistory = await sqliteDb.queryData(query, values) | ||
if (btHistory.length === 0) { | ||
return btHistory | ||
} | ||
const normalizedBtHistory = btHistory.map((bt) => { | ||
const parsedResult = bt?.btResult ? JSON.parse(bt.btResult) : {} | ||
return { | ||
...bt, | ||
btResult: parsedResult, | ||
// Transform binary values to boolean type after SQLite | ||
includeCandles: !!bt.includeCandles, | ||
includeTrades: !!bt.includeTrades, | ||
sync: !!bt.sync, | ||
isFavorite: !!bt.isFavorite | ||
} | ||
}) | ||
return normalizedBtHistory | ||
} | ||
|
||
const setBtFavorite = async (executionId, isFavorite) => { | ||
const query = 'update bt_history set isFavorite=? where executionId=?' | ||
const values = [isFavorite, executionId] | ||
await sqliteDb.executeQuery(query, values) | ||
} | ||
|
||
const deleteBt = async (executionId) => { | ||
const query = 'delete from bt_history where executionId=?' | ||
const values = [executionId] | ||
await sqliteDb.executeQuery(query, values) | ||
} | ||
|
||
const deleteAllBts = async (strategyId) => { | ||
const query = 'delete from bt_history where strategyId=?' | ||
const values = [strategyId] | ||
await sqliteDb.executeQuery(query, values) | ||
} | ||
|
||
module.exports = { saveBt, getBtHistory, setBtFavorite, deleteBt, deleteAllBts } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
'use strict' | ||
|
||
const debug = require('debug')('bfx:hf:data-server:db:sqlite_db') | ||
const Sqlite = require('bfx-facs-db-sqlite') | ||
let sqliteDb | ||
|
||
// connect to db | ||
const connectDb = async (sqlitePath) => { | ||
const opts = { name: 'hf_ds', label: '', dbPathAbsolute: sqlitePath } | ||
const sqlite = new Sqlite(this, opts, {}) | ||
|
||
return new Promise((resolve, reject) => { | ||
sqlite.start(async () => { | ||
if (!sqlite.db) reject(new Error('sqlite connection failed')) | ||
|
||
debug('sqlite connected') | ||
sqliteDb = sqlite.db | ||
// create tables after db connected | ||
await createTables() | ||
|
||
resolve(true) | ||
}) | ||
}) | ||
} | ||
|
||
const createTables = async () => { | ||
const createBTHistory = 'create table if not exists bt_history (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, exchange VARCHAR(20), strategyId VARCHAR(50), start INTEGER, end INTEGER, symbol VARCHAR(20), timeframe VARCHAR(10), includeCandles TINYINT(1), includeTrades TINYINT(1), candleSeed INTEGER, sync TINYINT(1), executionId VARCHAR(50), capitalAllocation DOUBLE, stopLossPerc DOUBLE, maxDrawdownPerc DOUBLE, isFavorite TINYINT(1), timestamp INTEGER, btResult TEXT)' | ||
await executeQuery(createBTHistory) | ||
} | ||
|
||
const createData = async (query, values = []) => { | ||
await executeQuery(query, values) | ||
} | ||
|
||
const executeQuery = async (query, values = []) => { | ||
if (!sqliteDb) return | ||
|
||
return new Promise((resolve, reject) => { | ||
sqliteDb.run(query, values, (err, data) => _handleDbCallback(err, data, resolve, reject)) | ||
}) | ||
} | ||
|
||
const getData = async (query, values = []) => { | ||
if (!sqliteDb) return | ||
|
||
return new Promise((resolve, reject) => { | ||
sqliteDb.get(query, values, (err, data) => _handleDbCallback(err, data, resolve, reject)) | ||
}) | ||
} | ||
|
||
const queryData = async (query, values = []) => { | ||
if (!sqliteDb) return | ||
|
||
return new Promise((resolve, reject) => { | ||
sqliteDb.all(query, values, (err, data) => _handleDbCallback(err, data, resolve, reject)) | ||
}) | ||
} | ||
|
||
const _handleDbCallback = (error, data, resolve, reject) => { | ||
if (error) { | ||
console.error(error) | ||
reject(new Error(error.toString())) | ||
} | ||
resolve(data) | ||
} | ||
|
||
module.exports = { connectDb, executeQuery, createData, getData, queryData } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.