Snapshots

This commit is contained in:
Luis Fernando Molina committed 2020-05-10 14:17:10 +02:00
1 parent 481986cc45
commit b69a9416ca
3 files changed
+172 -102

No files matched your search

+56 -84
View File
@@ -121,6 +121,7 @@
const CONDITIONS_FOLDER_NAME = "Simulation-Conditions";
const STRATEGIES_FOLDER_NAME = "Simulation-Strategies";
const TRADES_FOLDER_NAME = "Simulation-Trades";
const SNAPSHOTS_FOLDER_NAME = "Snapshots";
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
@@ -129,6 +130,10 @@
let strategiesArray
let tradesArray
let snapshotHeaders
let triggerOnSnapshot
let takePositionSnapshot
let tradingSystem = {};
tradingSimulation.runSimulation(
@@ -142,7 +147,7 @@
writeFiles,
callBackFunction)
function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray) {
function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pSnapshotHeaders, pTriggerOnSnapshot, pTakePositionSnapshot) {
tradingSystem = pTradingSystem
recordsArray = pRecordsArray
@@ -150,11 +155,16 @@
strategiesArray = pStrategiesArray
tradesArray = pTradesArray
snapshotHeaders = pSnapshotHeaders
triggerOnSnapshot = pTriggerOnSnapshot
takePositionSnapshot = pTakePositionSnapshot
if (timeFrame > global.dailyFilePeriods[0][0]) {
writeMarketFiles()
} else {
writeDailyFiles()
}
}
function writeMarketFiles() {
@@ -474,7 +484,7 @@
}
callBackFunction(global.DEFAULT_OK_RESPONSE);
writeSnapshotFiles();
}
catch (err) {
@@ -489,97 +499,52 @@
}
}
}
function writeSnapshotFiles() {
function writeDailyFiles() {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> Entering function."); }
writeSnapshotFile(triggerOnSnapshot, 'Trigger-On', onFinish)
writeRecordsFile();
function onFinish() {
writeSnapshotFile(takePositionSnapshot, 'Take-Position', callBackFunction)
}
}
/* TODO : NEXT function is a work in progress, not used today */
function writeFinalResults() {
function writeSnapshotFile(snapshotArray, pFileName, callBack) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> Entering function."); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeSnapshotFile -> Entering function."); }
if ( // We only write this file if we are at the head of the market.
Math.trunc(currentDay.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS
!==
Math.trunc((new Date()).valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS
) {
writeRecordsFile();
return;
}
let separator = "";
let fileRecordCounter = 0;
let fileContent = "";
let separator = "\r\n";
for (let i = 0; i < recordsArray.length; i++) {
let record = recordsArray[i];
/* Will only add to the file the records of the current day */
if (record.begin < currentDay.valueOf()) { continue; }
fileContent = fileContent + separator + '[' +
record.begin + "," +
record.end + "," +
record.type + "," +
record.marketRate + "," +
record.amount + "," +
record.balanceA + "," +
record.balanceB + "," +
record.profit + "," +
record.lastTradeProfitLoss + "," +
record.stopLoss + "," +
record.roundtrips + "," +
record.hits + "," +
record.fails + "," +
record.hitRatio + "," +
record.ROI + "," +
record.periods + "," +
record.days + "," +
record.anualizedRateOfReturn + "," +
record.positionRate + "," +
record.lastTradeROI + "," +
record.strategy + "," +
record.strategyStageNumber + "," +
record.takeProfit + "," +
record.stopLossPhase + "," +
record.takeProfitPhase + "," +
JSON.stringify(record.executionRecord) + "," +
record.positionSize + "," +
record.initialBalanceA + "," +
record.minimumBalanceA + "," +
record.maximumBalanceA + "," +
record.initialBalanceB + "," +
record.minimumBalanceB + "," +
record.maximumBalanceB + "," +
record.baseAsset + "," +
record.quotedAsset + "," +
record.marketBaseAsset + "," +
record.marketQuotedAsset + "," +
record.positionPeriods + "," +
record.positionDays + "," +
record.distanceToLastTriggerOn + "," +
record.distanceToLastTriggerOff + "," +
record.distanceToLastTakePosition + "," +
record.distanceToLastClosePosition + "]";
if (separator === "") { separator = ","; }
parseRecord(snapshotHeaders)
for (let i = 0; i < snapshotArray.length; i++) {
let record = snapshotArray[i];
parseRecord(record)
fileRecordCounter++;
}
function parseRecord(record) {
for (let j = 0; j < record.length; j++) {
let property = record[j]
fileContent = fileContent + '' + property
if (j !== record.length - 1) {
fileContent = fileContent + ","
}
}
fileContent = fileContent + separator
}
fileContent = "[" + fileContent + "]";
fileContent = "" + fileContent + "";
let fileName = 'Data.json';
let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + timeFrameLabel;
let fileName = pFileName + '.csv';
let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SNAPSHOTS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrameLabel;
filePath += '/' + fileName
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
@@ -588,35 +553,42 @@
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> Entering function."); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> fileContent = " + fileContent); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> Entering function."); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> fileContent = " + fileContent); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset);
logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset);
callBackFunction(err);
return;
}
writeRecordsFile();
callBack(global.DEFAULT_OK_RESPONSE);
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> onFileCreated -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> onFileCreated -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeDailyFiles -> writeFinalResults -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] start -> writeMarketFiles -> writeSnapshotFile -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
function writeDailyFiles() {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDailyFiles -> Entering function."); }
writeRecordsFile();
function writeRecordsFile() {
try {
+107 -9
View File
@@ -39,6 +39,10 @@
} else {
processingDailyFiles = true
}
let snapshotHeaders
let triggerOnSnapshot = [];
let takePositionSnapshot = [];
let recordsArray = [];
let conditionsArray = [];
@@ -500,6 +504,14 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Entering function."); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Processing candle # " + currentCandleIndex); }
/* We are going to take snapshots of the values of indicators at key moments of the sumulation. */
let snapshotKeys = new Map()
snapshotLoopHeaders = []
snapshotDataRecord = []
addToTriggerOnSnapshot = false
addToTakePositionSnapshot = false
let announcementsToBeMade = []
let candle = candles[currentCandleIndex];
@@ -767,7 +779,9 @@
if (initialDefinition.positionSize !== undefined) {
if (initialDefinition.positionSize.formula !== undefined) {
try {
positionSize = eval(initialDefinition.positionSize.formula.code);
let code = initialDefinition.positionSize.formula.code
positionSize = eval(code);
addCodeToSnapshot(code)
} catch (err) {
initialDefinition.positionSize.formula.error = err.message
}
@@ -794,7 +808,9 @@
if (initialDefinition.positionRate !== undefined) {
if (initialDefinition.positionRate.formula !== undefined) {
try {
let code = initialDefinition.positionRate.formula.code
positionRate = eval(initialDefinition.positionRate.formula.code);
addCodeToSnapshot(code)
} catch (err) {
initialDefinition.positionRate.formula.error = err.message
}
@@ -821,7 +837,9 @@
if (phase.formula !== undefined) {
try {
formulaValue = eval(phase.formula.code);
let code = phase.formula.code
formulaValue = eval(code);
addCodeToSnapshot(code)
if (formulaValue === Infinity) {
formulaError = "Formula evaluates to Infinity."
formulaValue = MAX_STOP_LOSS_VALUE
@@ -910,7 +928,9 @@
if (phase.formula !== undefined) {
try {
formulaValue = eval(phase.formula.code);
let code = phase.formula.code
formulaValue = eval(code);
addCodeToSnapshot(code)
if (formulaValue === Infinity) {
formulaValue = MAX_TAKE_PROFIT_VALUE
if (takeProfitStage === 'Open Stage') {
@@ -1007,7 +1027,9 @@
if (phase.formula !== undefined) {
try {
formulaValue = eval(phase.formula.code);
let code = phase.formula.code
formulaValue = eval(code);
addCodeToSnapshot(code)
if (formulaValue === Infinity) {
formulaError = ""
formulaValue = MAX_STOP_LOSS_VALUE
@@ -1096,7 +1118,9 @@
if (phase.formula !== undefined) {
try {
formulaValue = eval(phase.formula.code);
let code = phase.formula.code
formulaValue = eval(code);
addCodeToSnapshot(code)
if (formulaValue === Infinity) {
formulaError = "Formula evaluates to Infinity."
formulaValue = MAX_TAKE_PROFIT_VALUE
@@ -1181,7 +1205,9 @@
let value
try {
value = eval(node.code);
let code = node.code
value = eval(code);
addCodeToSnapshot(code)
} catch (err) {
/*
One possible error is that the conditions references a .previous that is undefined. For this
@@ -1319,6 +1345,7 @@
}
checkAnnouncements(triggerStage.triggerOn)
addToTriggerOnSnapshot = true
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met."); }
break;
@@ -1452,6 +1479,7 @@
currentTrade.takePositionSituation = situation.name
checkAnnouncements(triggerStage.takePosition)
addToTakePositionSnapshot = true
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met."); }
break;
@@ -2186,6 +2214,7 @@
}
takePositionAtSimulation()
return
function putOpeningOrder() {
@@ -2914,6 +2943,21 @@
}
}
/* Add to Snapshot */
if (addToTakePositionSnapshot === true) {
takePositionSnapshot.push(snapshotDataRecord)
addToTakePositionSnapshot = false
}
if (addToTriggerOnSnapshot === true) {
triggerOnSnapshot.push(snapshotDataRecord)
addToTriggerOnSnapshot = false
}
if (snapshotHeaders === undefined) {
snapshotHeaders = JSON.parse(JSON.stringify(snapshotLoopHeaders))
}
makeAnnoucements() // After everything at the simulation level was done, we will do the annoucements that are pending.
}
@@ -3005,10 +3049,63 @@
}
}
}
function addCodeToSnapshot(code) {
if (code === undefined) { return }
try {
let instructionsArray = code.split(' ')
for (let i = 0; i < instructionsArray.length; i++) {
let instruction = instructionsArray[i]
instruction = instruction.replace('(', '')
instruction = instruction.replace(')', '')
instruction = instruction.replace(/</g, '')
instruction = instruction.replace(/>/g, '')
instruction = instruction.replace(/<=/g, '')
instruction = instruction.replace(/>=/g, '')
instruction = instruction.replace(/!=/g, '')
instruction = instruction.replace(/!==/g, '')
instruction = instruction.replace(/==/g, '')
instruction = instruction.replace(/===/g, '')
if (instruction.indexOf('chart') >= 0) {
let parts = instruction.split('.')
let timeFrame = parts[1]
let product = parts[2]
let property
checkPrevious(3)
function checkPrevious(index) {
property = parts[index]
if (property === 'previous') {
product = product + '.previous'
checkPrevious(index + 1)
}
}
// Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10
if (timeFrame !== 'atAnyTimeFrame') {
timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7)
}
let key = timeFrame + '-' + product + '-' + property
let existingKey = snapshotKeys.get(key)
if (existingKey === undefined) {// means that at the current loop this property of this product was not used before.
snapshotKeys.set(key, key)
snapshotLoopHeaders.push(key)
let value = eval(instruction)
snapshotDataRecord.push(value)
}
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] runSimulation -> addCodeToSnapshot -> code = " + code);
logger.write(MODULE_NAME, "[ERROR] runSimulation -> addCodeToSnapshot -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
function controlLoop() {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> Entering function."); }
@@ -3114,7 +3211,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); }
callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray);
callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, snapshotHeaders, triggerOnSnapshot, takePositionSnapshot);
}
function getElement(pArray, currentCandle, datasetName) {
@@ -3156,6 +3253,7 @@
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] runSimulation -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
+9 -9
View File
@@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"ccxt": {
"version": "1.25.80",
"resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.25.80.tgz",
"integrity": "sha512-AUWagxMa8PMexRabbktWezlmVacj6L2Ep4844ebIXUOyME2Ommg7O/9/pq0F2Ne1IHcJnNJzHrMYQvkh2gBtlw=="
"version": "1.27.45",
"resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.27.45.tgz",
"integrity": "sha512-4ADlbcIWDzIWjtLvsrtux5jMFj7pU4kVuiqtI2Btq6NEhQ4r/4+LirXdEFlCF6/wIU3XSHabxMd/8nu8HC1KJw=="
},
"debug": {
"version": "4.1.1",
@@ -48,9 +48,9 @@
"integrity": "sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ=="
},
"telegraf": {
"version": "3.37.0",
"resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.37.0.tgz",
"integrity": "sha512-V3448qwfOolBqkIc87yxjW4zMvR2P6AIF24pPTlX9WhZPwA1TF/x3nQhnWPRLtGh2SJuvDcr83iTkXPXT7Opnw==",
"version": "3.38.0",
"resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.38.0.tgz",
"integrity": "sha512-va4VlrKWp64JrowFoZX/NPzzA6q38kvaIukVXOWFO1V+jR1G8+hCfgJy4TX8Z3rwLJzwaBEet1QhikHDRZWl3A==",
"requires": {
"debug": "4.1.1",
"minimist": "1.2.5",
@@ -66,9 +66,9 @@
"integrity": "sha512-njVv1EAhIZnmQVLocZEADYUyqA1WIXuVcDYlsp+mXua/XB0pxx+PKtMSPeZ/EE4wPWTw9h/hA9ASTT6yQelkiw=="
},
"ws": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz",
"integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ=="
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz",
"integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w=="
}
}
}