A lot of bugs fixed

This commit is contained in:
Luis Fernando Molina committed 2020-08-14 19:28:05 +02:00
1 parent 049e0d20a0
commit 593e53fea3
18 files changed
+765 -734

No files matched your search

@@ -6,9 +6,11 @@ exports.newTradingEngine = function newTradingEngine(bot, logger) {
const MODULE_NAME = 'Trading Engine'
let thisObject = {
mantain: mantain,
reset: reset,
getNodeById: getNodeById,
cloneValues: cloneValues,
setCurrentCandle: setCurrentCandle,
setCurrentCycle: setCurrentCycle,
initializeNode: initializeNode,
initialize: initialize,
finalize: finalize
@@ -46,6 +48,10 @@ exports.newTradingEngine = function newTradingEngine(bot, logger) {
updateDistanceToEventsCounters()
}
function reset() {
}
function getNodeById(NodeId) {
return nodesMap.get(NodeId)
}
@@ -59,6 +65,32 @@ exports.newTradingEngine = function newTradingEngine(bot, logger) {
tradingEngine.current.episode.candle.max.value = candle.max
}
function setCurrentCycle(cycle) {
switch (cycle) {
case 'First': {
tradingEngine.current.episode.cycle.begin.value =
tradingEngine.current.episode.candle.begin.value +
sessionParameters.timeFrame.config.value
tradingEngine.current.episode.cycle.end.value =
tradingEngine.current.episode.candle.begin.value +
sessionParameters.timeFrame.config.value +
sessionParameters.timeFrame.config.value / 2 - 1
break
}
case 'Second': {
tradingEngine.current.episode.cycle.begin.value =
tradingEngine.current.episode.candle.begin.value +
sessionParameters.timeFrame.config.value +
sessionParameters.timeFrame.config.value / 2
tradingEngine.current.episode.cycle.end.value =
tradingEngine.current.episode.candle.begin.value +
sessionParameters.timeFrame.config.value +
sessionParameters.timeFrame.config.value * 4 / 4 - 1
break
}
}
}
function cloneValues(originNode, destinationNode) {
if (originNode === undefined) { return }
if (destinationNode === undefined) { return }
@@ -5,6 +5,7 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
const MODULE_NAME = 'Trading Episode'
let thisObject = {
mantain: mantain,
reset: reset,
openEpisode: openEpisode,
updateExitType: updateExitType,
closeEpisode: closeEpisode,
@@ -33,12 +34,15 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
}
function mantain() {
resetTradingEngineDataStructure()
updateCounters()
updateStatistics()
updateEnds()
}
function reset() {
resetTradingEngineDataStructure()
}
function openEpisode() {
/*
This function is called each time the simulation starts. That does not mean the Episode
@@ -132,12 +136,12 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
tradingEngine.current.episode.episodeStatistics.ROI.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.ROI.value, 10)
/* Updating Anualized Rate Of Return */
tradingEngine.current.episode.episodeStatistics.anualizedRateOfReturn.value =
/* Updating Annualized Rate Of Return */
tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value =
tradingEngine.current.episode.episodeStatistics.ROI.value /
tradingEngine.current.episode.episodeStatistics.days.value * 365
tradingEngine.current.episode.episodeStatistics.anualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.anualizedRateOfReturn.value, 10)
tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value, 10)
/* Updating Hit or Fail */
if (tradingEngine.current.episode.episodeStatistics.profitLoss.value > 0) {
@@ -197,17 +201,17 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
tradingEngine.current.episode.episodeBaseAsset.hitRatio.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.hitRatio.value, 10)
tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value, 10)
/* Updating Anualized Rate Of Return */
tradingEngine.current.episode.episodeBaseAsset.anualizedRateOfReturn.value =
/* Updating Annualized Rate Of Return */
tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value =
tradingEngine.current.episode.episodeBaseAsset.ROI.value /
tradingEngine.current.episode.episodeStatistics.days.value * 365
tradingEngine.current.episode.episodeQuotedAsset.anualizedRateOfReturn.value =
tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value =
tradingEngine.current.episode.episodeQuotedAsset.ROI.value /
tradingEngine.current.episode.episodeStatistics.days.value * 365
tradingEngine.current.episode.episodeBaseAsset.anualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.anualizedRateOfReturn.value, 10)
tradingEngine.current.episode.episodeQuotedAsset.anualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.anualizedRateOfReturn.value, 10)
tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value, 10)
tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value, 10)
/* Updating Hit or Fail */
if (tradingEngine.current.episode.episodeBaseAsset.profitLoss.value > 0) {
@@ -6,6 +6,7 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
let thisObject = {
mantain: mantain,
reset: reset,
runExecution: runExecution,
initialize: initialize,
finalize: finalize
@@ -41,6 +42,10 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
tradingOrdersModule.mantain()
}
function reset() {
tradingOrdersModule.reset()
}
async function runExecution(
executionNode,
tradingEngineStage
+166 -100
View File
@@ -6,6 +6,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
let thisObject = {
mantain: mantain,
reset: reset,
checkOrders: checkOrders,
initialize: initialize,
finalize: finalize
@@ -45,6 +46,14 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
}
function mantain() {
mantainReset(true, false)
}
function reset() {
mantainReset(false, true)
}
function mantainReset(mantain, reset) {
if (tradingEngine.current.strategy.index.value === tradingEngine.current.strategy.index.config.initialValue) { return }
@@ -53,42 +62,46 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
executionNode = stageNode.openExecution
mantainExecutionNode(executionNode, tradingEngine.current.strategyOpenStage.status.value)
processExecutionNode(executionNode, tradingEngine.current.strategyOpenStage.status.value)
stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].closeStage
executionNode = stageNode.closeExecution
mantainExecutionNode(executionNode, tradingEngine.current.strategyCloseStage.status.value)
processExecutionNode(executionNode, tradingEngine.current.strategyCloseStage.status.value)
function mantainExecutionNode(executionNode, stageStatus) {
function processExecutionNode(executionNode, stageStatus) {
mantainExecutionAlgorithms(executionNode)
preocessExecutionAlgorithms(executionNode)
function mantainExecutionAlgorithms(executionNode) {
function preocessExecutionAlgorithms(executionNode) {
for (let i = 0; i < executionNode.executionAlgorithms.length; i++) {
let executionAlgorithm = executionNode.executionAlgorithms[i]
mantainOrders(executionAlgorithm.marketBuyOrders)
mantainOrders(executionAlgorithm.marketSellOrders)
mantainOrders(executionAlgorithm.limitBuyOrders)
mantainOrders(executionAlgorithm.limitSellOrders)
processOrders(executionAlgorithm.marketBuyOrders)
processOrders(executionAlgorithm.marketSellOrders)
processOrders(executionAlgorithm.limitBuyOrders)
processOrders(executionAlgorithm.limitSellOrders)
}
}
function mantainOrders(orders) {
function processOrders(orders) {
for (let i = 0; i < orders.length; i++) {
let tradingSystemOrder = orders[i]
if (tradingSystemOrder.referenceParent === undefined) { continue }
if (tradingSystemOrder.referenceParent === undefined) {
badDefinitionUnhandledException(undefined, 'tradingSystemOrder.referenceParent === undefined', tradingSystemOrder)
}
let tradingEngineOrder = tradingEngineModule.getNodeById(tradingSystemOrder.referenceParent.id)
try {
if (tradingEngineOrder.status === undefined) { continue }
} catch (err) {
console.log(err.stack)
if (tradingEngineOrder.status === undefined) {
badDefinitionUnhandledException(undefined, 'tradingEngineOrder.status === undefined', tradingEngineOrder)
}
updateCounters(tradingEngineOrder)
updateEnds(tradingEngineOrder)
updateStatistics(tradingEngineOrder)
resetTradingEngineDataStructure(tradingEngineOrder, tradingSystemOrder, stageStatus)
if (mantain === true) {
updateCounters(tradingEngineOrder)
updateEnds(tradingEngineOrder)
updateStatistics(tradingEngineOrder)
}
if (reset === true) {
resetTradingEngineDataStructure(tradingEngineOrder, tradingSystemOrder, stageStatus)
}
}
}
}
@@ -151,6 +164,8 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
/* Cancel the order at the Exchange, if needed. */
await exchangeCancelOrder(tradingEngineStage, tradingSystemOrder, tradingEngineOrder, 'Cancel Event')
updateEndsWithCycle(tradingEngineOrder)
}
}
}
@@ -216,8 +231,8 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
/* Create Order Procedure */
tradingEngineOrder.status.value = 'Open'
tradingEngineOrder.identifier.value = global.UNIQUE_ID()
tradingEngineOrder.begin.value = tradingEngine.current.episode.candle.begin.value
tradingEngineOrder.end.value = tradingEngine.current.episode.candle.end.value
tradingEngineOrder.begin.value = tradingEngine.current.episode.cycle.begin.value
tradingEngineOrder.end.value = tradingEngine.current.episode.cycle.end.value
tradingEngineOrder.serialNumber.value = tradingEngine.current.episode.episodeCounters.orders.value
tradingEngineOrder.orderName.value = tradingSystemOrder.name
tradingEngineOrder.algorithmName.value = executionAlgorithm.name
@@ -253,24 +268,42 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
if (tradingSystemOrder.config.percentageOfAlgorithmSize === undefined) { badDefinitionUnhandledException(undefined, 'tradingSystemOrder.config.percentageOfAlgorithmSize === undefined', tradingSystemOrder) }
if (isNaN(tradingSystemOrder.config.percentageOfAlgorithmSize) === true) { badDefinitionUnhandledException(undefined, 'isNaN(tradingSystemOrder.config.percentageOfAlgorithmSize) === true', tradingSystemOrder) }
/* Size in Base Asset */
tradingEngineOrder.orderBaseAsset.size.value = algorithmSizeInBaseAsset * tradingSystemOrder.config.percentageOfAlgorithmSize / 100
/*
The Size calculation depends on how the user defined the size of the position.
The user could have defined the size of the position in Base Asset or Quoted Asset.
*/
switch (tradingEngineStage.stageDefinedIn.value) {
case 'Base Asset': {
/* Size in Base Asset */
tradingEngineOrder.orderBaseAsset.size.value = algorithmSizeInBaseAsset * tradingSystemOrder.config.percentageOfAlgorithmSize / 100
/* Size in Quoted Asset */
tradingEngineOrder.orderQuotedAsset.size.value = algorithmSizeInQuotedAsset * tradingSystemOrder.config.percentageOfAlgorithmSize / 100
/* Check that the Size calculated would not surpass Stage Target Size */
if (
tradingEngineOrder.orderBaseAsset.size.value + tradingEngineStage.stageBaseAsset.sizePlaced.value >
tradingEngineStage.stageBaseAsset.targetSize.value
) {
tradingEngineOrder.orderBaseAsset.size.value = tradingEngineStage.stageBaseAsset.targetSize.value - tradingEngineStage.stageBaseAsset.sizePlaced.value
}
/* Check that the Size calculated would not surpass Stage Target Size */
if (
tradingEngineOrder.orderBaseAsset.size.value + tradingEngineStage.stageBaseAsset.sizePlaced.value >
tradingEngineStage.stageBaseAsset.targetSize.value
) {
tradingEngineOrder.orderBaseAsset.size.value = tradingEngineStage.stageBaseAsset.targetSize.value - tradingEngineStage.stageBaseAsset.sizePlaced.value
}
if (
tradingEngineOrder.orderQuotedAsset.size.value + tradingEngineStage.stageQuotedAsset.sizePlaced.value >
tradingEngineStage.stageQuotedAsset.targetSize.value
) {
tradingEngineOrder.orderQuotedAsset.size.value = tradingEngineStage.stageQuotedAsset.targetSize.value - tradingEngineStage.stageQuotedAsset.sizePlaced.value
/* Size in Quoted Asset */
tradingEngineOrder.orderQuotedAsset.size.value = tradingEngineOrder.orderBaseAsset.size.value * tradingEngineOrder.rate.value
break
}
case 'Quoted Asset': {
/* Size in Quoted Asset */
tradingEngineOrder.orderQuotedAsset.size.value = algorithmSizeInQuotedAsset * tradingSystemOrder.config.percentageOfAlgorithmSize / 100
if (
tradingEngineOrder.orderQuotedAsset.size.value + tradingEngineStage.stageQuotedAsset.sizePlaced.value >
tradingEngineStage.stageQuotedAsset.targetSize.value
) {
tradingEngineOrder.orderQuotedAsset.size.value = tradingEngineStage.stageQuotedAsset.targetSize.value - tradingEngineStage.stageQuotedAsset.sizePlaced.value
}
/* Size in Base Asset */
tradingEngineOrder.orderBaseAsset.size.value = tradingEngineOrder.orderQuotedAsset.size.value / tradingEngineOrder.rate.value
break
}
}
tradingEngineOrder.orderBaseAsset.size.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.size.value, 10)
@@ -333,8 +366,8 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
let previousQuotedAssetFeesPaid = tradingEngineOrder.orderQuotedAsset.feesPaid.value
actualRateSimulation()
feesPaidSimulation()
percentageFilledSimulation()
feesPaidSimulation()
sizeFilledSimulation()
doTheAccounting(
@@ -397,67 +430,6 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
tradingEngineOrder.orderStatistics.actualRate.value = global.PRECISE(tradingEngineOrder.orderStatistics.actualRate.value, 10)
}
function feesPaidSimulation() {
/* Fees Paid Simulation */
let calculatedBasedOnTradingSystem = false
/* Based on the Trading System Definition */
if (tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid !== undefined) {
if (tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid.config.percentage !== undefined) {
if (tradingEngineOrder.orderBaseAsset.feesPaid.value === tradingEngineOrder.orderBaseAsset.feesPaid.config.initialValue) {
tradingEngineOrder.orderBaseAsset.feesPaid.value =
tradingEngineOrder.orderBaseAsset.size.value *
tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid.config.percentage / 100
calculatedBasedOnTradingSystem = true
}
if (tradingEngineOrder.orderQuotedAsset.feesPaid.value === tradingEngineOrder.orderQuotedAsset.feesPaid.config.initialValue) {
tradingEngineOrder.orderQuotedAsset.feesPaid.value =
tradingEngineOrder.orderQuotedAsset.size.value *
tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid.config.percentage / 100
calculatedBasedOnTradingSystem = true
}
}
}
/* Based on the Session Parameters Definition */
if (calculatedBasedOnTradingSystem === false) {
/* Fees are simulated based on the Session Paremeters */
switch (tradingEngineOrder.type) {
case 'Market Order': {
tradingEngineOrder.orderBaseAsset.feesPaid.value =
tradingEngineOrder.orderBaseAsset.size.value *
bot.SESSION.parameters.feeStructure.config.taker / 100
tradingEngineOrder.orderQuotedAsset.feesPaid.value =
tradingEngineOrder.orderQuotedAsset.size.value *
bot.SESSION.parameters.feeStructure.config.taker / 100
break
}
case 'Limit Order': {
tradingEngineOrder.orderBaseAsset.feesPaid.value =
tradingEngineOrder.orderBaseAsset.size.value *
bot.SESSION.parameters.feeStructure.config.maker / 100
tradingEngineOrder.orderQuotedAsset.feesPaid.value =
tradingEngineOrder.orderQuotedAsset.size.value *
bot.SESSION.parameters.feeStructure.config.maker / 100
break
}
}
}
tradingEngineOrder.orderBaseAsset.feesPaid.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.feesPaid.value, 10)
tradingEngineOrder.orderQuotedAsset.feesPaid.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.feesPaid.value, 10)
}
function percentageFilledSimulation() {
/*
Order Filling Simulation: the way we are going to handle this is the following.
@@ -481,6 +453,14 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
}
break
}
case 'Market Buy Order': {
orderWasHit = true
break
}
case 'Market Sell Order': {
orderWasHit = true
break
}
}
if (orderWasHit === true) {
if (tradingSystemOrder.simulatedExchangeEvents.simulatedPartialFill !== undefined) {
@@ -507,10 +487,86 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
/* Initialize this */
tradingEngine.current.episode.distanceToEvent.closeOrder.value = 1
updateEndsWithCycle(tradingEngineOrder)
}
}
}
function feesPaidSimulation() {
/*
The way the fess paid is calculated is as follows: From the order size we apply the % of fee,
that would give us the total fees for that order. To that we apply the % filled of the orders,
that give use the final result of the fees paid for the current % filled.
But before that, we will see if there is an specific definition on how to simulate the fees for
this order, or if there is not, we use the fees session parameters definitions.
*/
let calculatedBasedOnTradingSystem = false
/* Based on the Trading System Definition */
if (tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid !== undefined) {
if (tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid.config.percentage !== undefined) {
if (tradingEngineOrder.orderBaseAsset.feesPaid.value === tradingEngineOrder.orderBaseAsset.feesPaid.config.initialValue) {
tradingEngineOrder.orderBaseAsset.feesPaid.value =
tradingEngineOrder.orderBaseAsset.size.value *
tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid.config.percentage / 100 *
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
calculatedBasedOnTradingSystem = true
}
if (tradingEngineOrder.orderQuotedAsset.feesPaid.value === tradingEngineOrder.orderQuotedAsset.feesPaid.config.initialValue) {
tradingEngineOrder.orderQuotedAsset.feesPaid.value =
tradingEngineOrder.orderQuotedAsset.size.value *
tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid.config.percentage / 100 *
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
calculatedBasedOnTradingSystem = true
}
}
}
/* Based on the Session Parameters Definition */
if (calculatedBasedOnTradingSystem === false) {
/* Fees are simulated based on the Session Paremeters */
switch (tradingEngineOrder.type) {
case 'Market Order': {
tradingEngineOrder.orderBaseAsset.feesPaid.value =
tradingEngineOrder.orderBaseAsset.size.value *
bot.SESSION.parameters.feeStructure.config.taker / 100 *
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
tradingEngineOrder.orderQuotedAsset.feesPaid.value =
tradingEngineOrder.orderQuotedAsset.size.value *
bot.SESSION.parameters.feeStructure.config.taker / 100 *
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
break
}
case 'Limit Order': {
tradingEngineOrder.orderBaseAsset.feesPaid.value =
tradingEngineOrder.orderBaseAsset.size.value *
bot.SESSION.parameters.feeStructure.config.maker / 100 *
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
tradingEngineOrder.orderQuotedAsset.feesPaid.value =
tradingEngineOrder.orderQuotedAsset.size.value *
bot.SESSION.parameters.feeStructure.config.maker / 100 *
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
break
}
}
}
tradingEngineOrder.orderBaseAsset.feesPaid.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.feesPaid.value, 10)
tradingEngineOrder.orderQuotedAsset.feesPaid.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.feesPaid.value, 10)
}
function sizeFilledSimulation() {
/* Size Filled */
tradingEngineOrder.orderBaseAsset.sizeFilled.value =
@@ -563,6 +619,8 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
/* Initialize this */
tradingEngine.current.episode.distanceToEvent.closeOrder.value = 1
updateEndsWithCycle(tradingEngineOrder)
}
if (order.remaining > 0 && order.status === AT_EXCHANGE_STATUS.CLOSED) {
@@ -572,6 +630,8 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
/* Initialize this */
tradingEngine.current.episode.distanceToEvent.closeOrder.value = 1
updateEndsWithCycle(tradingEngineOrder)
}
if (order.status === AT_EXCHANGE_STATUS.CANCELLED) {
@@ -581,6 +641,8 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
/* Initialize this */
tradingEngine.current.episode.distanceToEvent.closeOrder.value = 1
updateEndsWithCycle(tradingEngineOrder)
}
syncWithExchange(tradingEngineStage, tradingSystemOrder, tradingEngineOrder, order)
@@ -891,6 +953,10 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
}
}
function updateEndsWithCycle(tradingEngineOrder) {
tradingEngineOrder.end.value = tradingEngine.current.episode.cycle.end.value
}
function updateCounters(tradingEngineOrder) {
if (tradingEngineOrder.status.value === 'Open') {
tradingEngineOrder.orderCounters.periods.value++
@@ -5,6 +5,7 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
const MODULE_NAME = 'Trading Position'
let thisObject = {
mantain: mantain,
reset: reset,
openPosition: openPosition,
closingPosition: closingPosition,
closePosition: closePosition,
@@ -39,34 +40,39 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
}
function mantain() {
resetTradingEngineDataStructure()
updateCounters()
updateEnds()
}
function reset() {
resetTradingEngineDataStructure()
}
function openPosition(situationName) {
/* Recording the opening at the Trading Engine Data Structure */
tradingEngine.current.position.status.value = 'Open'
tradingEngine.current.position.serialNumber.value = tradingEngine.current.episode.episodeCounters.positions.value
tradingEngine.current.position.serialNumber.value = tradingEngine.current.episode.episodeCounters.positions.value + 1
tradingEngine.current.position.identifier.value = global.UNIQUE_ID()
tradingEngine.current.position.begin.value = tradingEngine.current.episode.candle.begin.value
tradingEngine.current.position.begin.value = tradingEngine.current.episode.candle.end.value
tradingEngine.current.position.beginRate.value = tradingEngine.current.episode.candle.close.value
tradingEngine.current.position.positionBaseAsset.beginBalance.value = tradingEngine.current.episode.episodeBaseAsset.balance.value
tradingEngine.current.position.positionQuotedAsset.beginBalance.value = tradingEngine.current.episode.episodeQuotedAsset.balance.value
tradingEngine.current.position.situationName.value = situationName
/* Initializing Stop and Take Profit Stage / Phase */
tradingEngine.current.position.stopLoss.stopLossStage.value = 'Open Stage'
tradingEngine.current.position.takeProfit.takeProfitStage.value = 'Open Stage'
tradingEngine.current.position.stopLoss.stopLossPhase.value = 0
tradingEngine.current.position.takeProfit.takeProfitPhase.value = 0
/* Initializing Stop and Take Phase */
tradingEngine.current.position.stopLoss.stopLossPhase.value = 1
tradingEngine.current.position.takeProfit.takeProfitPhase.value = 1
/* Updating Episode Counters */
tradingEngine.current.episode.episodeCounters.positions.value++
/* Inicializing this counter */
tradingEngine.current.episode.distanceToEvent.takePosition.value = 1
/* Remember the balance we had before taking the position to later calculate profit or loss */
tradingEngine.current.position.positionBaseAsset.beginBalance = tradingEngine.current.episode.episodeBaseAsset.balance.value
tradingEngine.current.position.positionQuotedAsset.beginBalance = tradingEngine.current.episode.episodeQuotedAsset.balance.value
}
function closingPosition(exitType) {
@@ -98,47 +104,45 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
tradingEngine.current.position.takeProfit.value = formulas.get(formulaId)
}
function updateStopLoss(phase, stage) {
function updateStopLoss(phase) {
tradingEngine.current.position.stopLoss.stopLossPhase.value = phase
tradingEngine.current.position.stopLoss.stopLossStage.value = stage
}
function updateTakeProfit(phase, stage) {
function updateTakeProfit(phase) {
tradingEngine.current.position.takeProfit.takeProfitPhase.value = phase
tradingEngine.current.position.takeProfit.takeProfitStage.value = stage
}
function initialTargets(stageNode) {
function initialTargets(tradingSystemStageNode, tradingEngineStageNode) {
if (stageNode.initialTargets === undefined) {
if (tradingSystemStageNode.initialTargets === undefined) {
const message = 'Stage without Initial Targets node. Add one please.'
badDefinitionUnhandledException(undefined, message, stageNode)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode)
}
setTargetRate()
setTargetSize()
function setTargetRate() {
if (stageNode.initialTargets.targetRate === undefined) {
if (tradingSystemStageNode.initialTargets.targetRate === undefined) {
const message = 'Target Rate Node not Found. Fix this please.'
badDefinitionUnhandledException(undefined, message, stageNode.initialTargets)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets)
}
if (stageNode.initialTargets.targetRate.formula === undefined) {
if (tradingSystemStageNode.initialTargets.targetRate.formula === undefined) {
const message = 'Formula of Target Rate Node not Found. Fix this please.'
badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetRate)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetRate)
}
let value = tradingSystem.formulas.get(stageNode.initialTargets.targetRate.formula.id)
let value = tradingSystem.formulas.get(tradingSystemStageNode.initialTargets.targetRate.formula.id)
if (value === undefined) {
const message = 'Target Rate can not be undefined. Fix this please.'
badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetRate.formula)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetRate.formula)
}
if (isNaN(value)) {
const message = 'Target Rate must be a number. Fix this please.'
badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetRate.formula)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetRate.formula)
}
switch (stageNode.type) {
switch (tradingSystemStageNode.type) {
case 'Open Stage': {
tradingEngine.current.position.entryTargetRate.value = global.PRECISE(value, 10)
break
@@ -153,27 +157,27 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
function setTargetSize() {
/* Basic Validation */
if (
stageNode.initialTargets.targetSizeInBaseAsset !== undefined &&
stageNode.initialTargets.targetSizeInQuotedAsset !== undefined
tradingSystemStageNode.initialTargets.targetSizeInBaseAsset !== undefined &&
tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset !== undefined
) {
const message = 'Only Target Size In Base Asset or Target Size In Quoted Asset is allowed. Remove one of them please.'
badDefinitionUnhandledException(undefined, message, stageNode)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode)
}
/* Position In Base Asset */
if (stageNode.initialTargets.targetSizeInBaseAsset !== undefined) {
if (stageNode.initialTargets.targetSizeInBaseAsset.formula !== undefined) {
let value = tradingSystem.formulas.get(stageNode.initialTargets.targetSizeInBaseAsset.formula.id)
if (tradingSystemStageNode.initialTargets.targetSizeInBaseAsset !== undefined) {
if (tradingSystemStageNode.initialTargets.targetSizeInBaseAsset.formula !== undefined) {
let value = tradingSystem.formulas.get(tradingSystemStageNode.initialTargets.targetSizeInBaseAsset.formula.id)
if (value === undefined) {
const message = 'Target Size In Base Asset cannot be undefined. Fix this please.'
badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetSizeInBaseAsset.formula)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInBaseAsset.formula)
}
if (value === undefined) {
const message = 'Target Size In Base Asset cannot be zero. Fix this please.'
badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetSizeInBaseAsset.formula)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInBaseAsset.formula)
}
switch (stageNode.type) {
switch (tradingSystemStageNode.type) {
case 'Open Stage': {
tradingEngine.current.position.positionBaseAsset.entryTargetSize.value = global.PRECISE(value, 10)
tradingEngine.current.position.positionQuotedAsset.entryTargetSize.value =
@@ -187,25 +191,28 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
break
}
}
/* Remember how the end user defined this stage. */
tradingEngineStageNode.stageDefinedIn.value = 'Base Asset'
} else {
const message = 'You need to specify a Formula for this.'
badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetSizeInBaseAsset)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInBaseAsset)
}
}
/* Position In Quoted Asset */
if (stageNode.initialTargets.targetSizeInQuotedAsset !== undefined) {
if (stageNode.initialTargets.targetSizeInQuotedAsset.formula !== undefined) {
let value = tradingSystem.formulas.get(stageNode.initialTargets.targetSizeInQuotedAsset.formula.id)
if (tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset !== undefined) {
if (tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset.formula !== undefined) {
let value = tradingSystem.formulas.get(tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset.formula.id)
if (value === undefined) {
const message = 'Target Size In Quoted Asset cannot be undefined. Fix this please.'
badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetSizeInQuotedAsset.formula)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset.formula)
}
if (value === undefined) {
const message = 'Target Size In Quoted Asset cannot be zero. Fix this please.'
badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetSizeInQuotedAsset.formula)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset.formula)
}
switch (stageNode.type) {
switch (tradingSystemStageNode.type) {
case 'Open Stage': {
tradingEngine.current.position.positionQuotedAsset.entryTargetSize.value = global.PRECISE(value, 10)
tradingEngine.current.position.positionBaseAsset.entryTargetSize.value =
@@ -219,9 +226,12 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
break
}
}
/* Remember how the end user defined this stage. */
tradingEngineStageNode.stageDefinedIn.value = 'Quoted Asset'
} else {
const errorText = 'You need to specify a Formula for this.'
badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetSizeInQuotedAsset.formula)
badDefinitionUnhandledException(undefined, message, tradingSystemStageNode.initialTargets.targetSizeInQuotedAsset.formula)
}
}
}
@@ -31,7 +31,7 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
outputDatasetsMap = undefined
}
function appendRecords() {
function appendRecords(cycle) {
/*
Here we add records to the output files. At the product config property nodePath
we have a pointer to the node that have the information we need to extract.
@@ -53,6 +53,14 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
}
function persistRecords() {
/*
There are a few products configured to be saved only at an specific cycle.
*/
if (product.config.saveAtCycle !== undefined) {
if (cycle !== product.config.saveAtCycle) {
return
}
}
/* Clean the file from information of previous executions */
pruneOutputFile(product, outputDatasetArray)
@@ -329,7 +337,12 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
let end = record[j]
if (end >= tradingEngine.current.episode.candle.end.value) {
outputFile.splice(i, 1)
pruneOutputFile(product, outputFile)
/*
This will execute the next prune call in the next iteration of the NodeJs event loop
allowing for other callbacks to be executed. It also prevents the error
'Maximum call stack size exceeded', since the call is not placed at the call stack.
*/
setImmediate(pruneOutputFile, product, outputFile)
return
}
}
@@ -137,16 +137,43 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
/* The chart was recalculated based on the current candle. */
tradingSystemModule.updateChart(chart)
/* Do the stuff needed previous to the run */
/*
Do the stuff needed previous to the run like
Episode Counters and Statistics update
*/
tradingSystemModule.mantain()
/* Episode Counters and Statistics update */
tradingEpisodeModule.mantain()
/* Run your maintaince procedure */
tradingEngineModule.mantain()
/* Run one cycle of the Trading System*/
/* Reset Data Structures */
tradingSystemModule.reset()
tradingEpisodeModule.reset()
tradingEngineModule.reset()
/*
Run the first cycle of the Trading System. In this first cycle we
give some room so that orders can be canceled or filled and we can
write those records into the output memory.
*/
tradingEngineModule.setCurrentCycle('First')
await tradingSystemModule.run()
/* Add new records to the process output */
tradingRecordsModule.appendRecords('First')
/* Reset Data Structures */
tradingSystemModule.reset()
tradingEpisodeModule.reset()
tradingEngineModule.reset()
/*
Run the second cycle of the Trading System. During this second run
some new orders might be created at slots freed up during the first
run. This allows for example for an Limit Order to be cancelled during the
first run, and the same Limit Order definition to spawn a new order
without the need to wait until the next candle.
*/
tradingEngineModule.setCurrentCycle('Second')
await tradingSystemModule.run()
controlLoop()
@@ -171,11 +198,16 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
if (tradingEngine.current.episode.candle.index.value + 1 < candles.length) {
/* Add new records to the process output */
tradingRecordsModule.appendRecords()
tradingRecordsModule.appendRecords('Second')
tradingEngine.current.episode.candle.index.value++
setImmediate(loop) // This will execute the next loop in the next iteration of the NodeJs event loop allowing for other callbacks to be executed.
/*
This will execute the next loop in the next iteration of the NodeJs event loop
allowing for other callbacks to be executed. It also prevents the error
'Maximum call stack size exceeded', since the call is not placed at the call stack.
*/
setImmediate(loop)
} else {
updateEpisode('All Candles Processed')
}
@@ -186,7 +218,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
tradingEpisodeModule.closeEpisode()
/* Add new records to the process output */
tradingRecordsModule.appendRecords()
tradingRecordsModule.appendRecords('Second')
afterLoop()
}
@@ -195,7 +227,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
tradingEpisodeModule.updateExitType(exitType)
/* Add new records to the process output */
tradingRecordsModule.appendRecords()
tradingRecordsModule.appendRecords('Second')
afterLoop()
}
+283 -324
View File
@@ -6,6 +6,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
let thisObject = {
updateChart: updateChart,
mantain: mantain,
reset: reset,
runTriggerStage: runTriggerStage,
runOpenStage: runOpenStage,
runManageStage: runManageStage,
@@ -88,11 +89,18 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
tradingStrategyModule.mantain()
tradingExecutionModule.mantain()
resetTradingEngineDataStructure()
updateCounters()
updateEnds()
}
function reset() {
tradingPositionModule.reset()
tradingStrategyModule.reset()
tradingExecutionModule.reset()
resetTradingEngineDataStructure()
}
function runTriggerStage() {
/*
We check if we will be triggering on, off or taking position.
@@ -251,149 +259,119 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
}
async function runOpenStage() {
/* Abort Open Stage Check */
if (tradingEngine.current.strategyOpenStage.status.value === 'Open' && tradingEngine.current.strategyCloseStage.status.value === 'Open') {
/*
if the Close stage is opened while the open stage is still open that means that
we need to stop placing orders, check what happened to the orders already placed,
and cancel all unfilled limit orders. We call this the Closing status of the Open Stage.
*/
changeStageStatus('Open Stage', 'Closing')
}
/* Opening Status Procedure */
if (tradingEngine.current.strategyOpenStage.status.value === 'Opening') {
checkIfWeNeedToAbortTheStage()
runWhenStatusIsOpening()
await runWhenStatusIsOpen()
await runWhenStatusIsClosing()
/* This procedure is intended to run only once */
let stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
let executionNode = stageNode.openExecution
/* Reset the Exchange Orders data structure to its initial value */
tradingEngineModule.initializeNode(tradingEngine.exchangeOrders)
tradingSystem.evalConditions(stageNode, 'Initial Definition')
tradingSystem.evalFormulas(stageNode, 'Initial Definition')
/* Remember the balance we had before taking the position to later calculate profit or loss */
tradingEngine.current.position.positionBaseAsset.beginBalance = tradingEngine.current.episode.episodeBaseAsset.balance.value
tradingEngine.current.position.positionQuotedAsset.beginBalance = tradingEngine.current.episode.episodeQuotedAsset.balance.value
/* Entry Position size and rate */
tradingSystem.evalFormulas(stageNode, 'Initial Targets')
tradingPositionModule.initialTargets(stageNode)
initializeStageTargetSize()
/* Check Execution at open stage node */
tradingSystem.evalConditions(stageNode, 'Open Execution')
tradingSystem.evalFormulas(stageNode, 'Open Execution')
await tradingExecutionModule.runExecution(
executionNode,
tradingEngine.current.strategyOpenStage
)
/* From here on, the state is officialy Open */
changeStageStatus('Open Stage', 'Open')
return
}
/* Open Status Procedure */
if (tradingEngine.current.strategyOpenStage.status.value === 'Open') {
/*
While the Open Stage is Open, we do our regular stuff: place orders and check
what happened to the orders already placed.
*/
let stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
let executionNode = stageNode.openExecution
/* Every Loop Cycle Activity */
tradingSystem.evalConditions(stageNode, 'Open Execution')
tradingSystem.evalFormulas(stageNode, 'Open Execution')
await tradingExecutionModule.runExecution(
executionNode,
tradingEngine.current.strategyOpenStage
)
/*
The Open is finished when the placedSize reaches the targetSize in any of the
stage assets, and the fillSize + feesPaid reaches the placedSize also in any
of the stage Assets.
This can happens at any time when we update the sizeFilled and the feesPaid values
when we see at the exchange that orders were filled.
*/
if (
(
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizePlaced >=
tradingEngine.current.strategyOpenStage.stageBaseAsset.targetSize
||
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizePlaced >=
tradingEngine.current.strategyOpenStage.stageQuotedAsset.targetSize
)
&&
(
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled.value +
tradingEngine.current.strategyOpenStage.stageBaseAsset.feesPaid.value >=
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizePlaced.value
||
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizeFilled.value +
tradingEngine.current.strategyOpenStage.stageQuotedAsset.feesPaid.value >=
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizePlaced.value
)
) {
changeStageStatus('Open Stage', 'Closed', 'Position Size Filled')
} else {
/* Check the Close Stage Event */
tradingSystem.evalConditions(stageNode, 'Close Stage Event')
if (checkStopStageEvent(stageNode) === true) {
changeStageStatus('Open Stage', 'Closing', 'Close Stage Event')
}
function checkIfWeNeedToAbortTheStage() {
/* Abort Open Stage Check */
if (tradingEngine.current.strategyOpenStage.status.value === 'Open' && tradingEngine.current.strategyCloseStage.status.value === 'Open') {
/*
if the Close stage is opened while the open stage is still open that means that
we need to stop placing orders, check what happened to the orders already placed,
and cancel all unfilled limit orders. We call this the Closing status of the Open Stage.
*/
changeStageStatus('Open Stage', 'Closing')
}
}
/* Closing Status Procedure */
if (tradingEngine.current.strategyOpenStage.status.value === 'Closing') {
/*
During the closing stage status, we do not place new orders, just check
if the ones placed were filled, and cancel the ones not filled.
*/
let stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
let executionNode = stageNode.openExecution
function runWhenStatusIsOpening() {
/* Opening Status Procedure */
if (tradingEngine.current.strategyOpenStage.status.value === 'Opening') {
/*
Check if there are unfilled orders, we will check if they were executed,
and cancel the ones that were not.
*/
tradingSystem.evalConditions(stageNode, 'Open Execution')
tradingSystem.evalFormulas(stageNode, 'Open Execution')
/* This procedure is intended to run only once */
let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
let tradingEngineStage = tradingEngine.current.strategyOpenStage
await tradingExecutionModule.runExecution(
executionNode,
tradingEngine.current.strategyOpenStage
)
/* Reset the Exchange Orders data structure to its initial value */
tradingEngineModule.initializeNode(tradingEngine.exchangeOrders)
/*
The Closing is finished when the fillSize + feesPaid reaches the ordersSize.
This can happens either because we update the sizeFilled value when we see
at the exchange that orders were filled, or we reduce the ordersSize when
we cancel not yet filled orders. Here it does not matter the targetSize since
this status represent a force closure of this stage.
*/
if (
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled.value +
tradingEngine.current.strategyOpenStage.stageBaseAsset.feesPaid.value >=
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizePlaced.value
/* Entry Position size and rate */
tradingSystem.evalFormulas(tradingSystemStage, 'Initial Targets')
tradingPositionModule.initialTargets(tradingSystemStage, tradingEngineStage)
initializeStageTargetSize()
||
/* From here on, the stage is officialy Open */
changeStageStatus('Open Stage', 'Open')
}
}
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizeFilled.value +
tradingEngine.current.strategyOpenStage.stageQuotedAsset.feesPaid.value >=
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizePlaced.value
) {
changeStageStatus('Open Stage', 'Closed')
async function runWhenStatusIsOpen() {
/* Open Status Procedure */
if (tradingEngine.current.strategyOpenStage.status.value === 'Open') {
/*
While the Open Stage is Open, we do our regular stuff: place orders and check
what happened to the orders already placed.
*/
let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
let tradingEngineStage = tradingEngine.current.strategyOpenStage
let executionNode = tradingSystemStage.openExecution
/* Evaluate conditions and formulas so they are ready during the execution run */
tradingSystem.evalConditions(executionNode, 'Open Execution')
tradingSystem.evalFormulas(executionNode, 'Open Execution')
await tradingExecutionModule.runExecution(
executionNode,
tradingEngineStage
)
checkIfStageNeedsToBeClosed(tradingEngineStage, tradingSystemStage, 'Open Stage')
}
}
async function runWhenStatusIsClosing() {
/* Closing Status Procedure */
if (tradingEngine.current.strategyOpenStage.status.value === 'Closing') {
/*
During the closing stage status, we do not place new orders, just check
if the ones placed were filled, and cancel the ones not filled.
*/
let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
let executionNode = tradingSystemStage.openExecution
/*
Check if there are unfilled orders, we will check if they were executed,
and cancel the ones that were not.
*/
tradingSystem.evalConditions(tradingSystemStage, 'Open Execution')
tradingSystem.evalFormulas(tradingSystemStage, 'Open Execution')
await tradingExecutionModule.runExecution(
executionNode,
tradingEngine.current.strategyOpenStage
)
/*
The Closing is finished when the sizeFilled + feesPaid reaches the sizePlaced.
This can happens either because we update the sizeFilled value when we see
at the exchange that orders were filled, or we reduce the sizePlaced when
we cancel not yet filled orders. Here it does not matter the targetSize since
this status represent a force closure of this stage.
*/
switch (tradingEngine.current.strategyOpenStage.stageDefinedIn.value) {
case 'Base Asset': {
if (
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled.value +
tradingEngine.current.strategyOpenStage.stageBaseAsset.feesPaid.value >=
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizePlaced.value
) {
changeStageStatus('Open Stage', 'Closed')
}
break
}
case 'Quoted Asset': {
if (
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizeFilled.value +
tradingEngine.current.strategyOpenStage.stageQuotedAsset.feesPaid.value >=
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizePlaced.value
) {
changeStageStatus('Open Stage', 'Closed')
}
break
}
}
}
}
@@ -410,57 +388,50 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
}
function runManageStage() {
/* Opening Status Procedure */
if (tradingEngine.current.strategyManageStage.status.value === 'Opening') {
/* We jump the management at the loop cycle where the position is being taken. */
changeStageStatus('Manage Stage', 'Open')
return
runWhenStatusIsOpening()
runWhenStatusIsOpen()
function runWhenStatusIsOpening() {
/* Opening Status Procedure */
if (tradingEngine.current.strategyManageStage.status.value === 'Opening') {
/* Now we switch to the Open status. */
changeStageStatus('Manage Stage', 'Open')
}
}
/* Open Status Procedure */
if (tradingEngine.current.strategyManageStage.status.value === 'Open') {
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
let manageStage = strategy.manageStage
tradingSystem.evalConditions(manageStage, 'Manage Stage')
tradingSystem.evalFormulas(manageStage, 'Manage Stage')
function runWhenStatusIsOpen() {
/* Open Status Procedure */
if (tradingEngine.current.strategyManageStage.status.value === 'Open') {
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
let manageStage = strategy.manageStage
if (
tradingEngine.current.position.stopLoss.stopLossStage.value === 'Open Stage' ||
tradingEngine.current.position.takeProfit.takeProfitStage.value === 'Open Stage') {
let stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
tradingSystem.evalConditions(stageNode, 'Initial Definition')
tradingSystem.evalFormulas(stageNode, 'Initial Definition')
/* Evaluate all the stage conditions and formulas to have them ready */
tradingSystem.evalConditions(manageStage, 'Manage Stage')
tradingSystem.evalFormulas(manageStage, 'Manage Stage')
/* Stop Loss Management */
checkStopPhasesEvents()
calculateStopLoss()
calculateStopLossPosition()
/* Take Profit Management */
checkTakeProfitPhaseEvents()
calculateTakeProfit()
calculateTakeProfitPosition()
/* Checking if Stop or Take Profit were hit */
checkStopLossOrTakeProfitWasHit()
}
/* Stop Loss Management */
checkStopPhasesEvents()
calculateStopLoss()
calculateStopLossPosition()
/* Take Profit Management */
checkTakeProfitPhaseEvents()
calculateTakeProfit()
calculateTakeProfitPosition()
/* Checking if Stop or Take Profit were hit */
checkStopLossOrTakeProfitWasHit()
}
function calculateStopLoss() {
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
let openStage = strategy.openStage
let manageStage = strategy.manageStage
let phase
if (tradingEngine.current.position.stopLoss.stopLossStage.value === 'Open Stage' && openStage !== undefined) {
if (openStage.initialDefinition !== undefined) {
if (openStage.initialDefinition.initialStopLoss !== undefined) {
phase = openStage.initialDefinition.initialStopLoss.phases[tradingEngine.current.position.stopLoss.stopLossPhase.value]
}
}
}
if (tradingEngine.current.position.stopLoss.stopLossStage.value === 'Manage Stage' && manageStage !== undefined) {
if (manageStage !== undefined) {
if (manageStage.managedStopLoss !== undefined) {
phase = manageStage.managedStopLoss.phases[tradingEngine.current.position.stopLoss.stopLossPhase.value - 1]
}
@@ -480,19 +451,10 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
function calculateTakeProfit() {
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
let openStage = strategy.openStage
let manageStage = strategy.manageStage
let phase
if (tradingEngine.current.position.takeProfit.takeProfitStage.value === 'Open Stage' && openStage !== undefined) {
if (openStage.initialDefinition !== undefined) {
if (openStage.initialDefinition.initialTakeProfit !== undefined) {
phase = openStage.initialDefinition.initialTakeProfit.phases[tradingEngine.current.position.takeProfit.takeProfitPhase.value]
}
}
}
if (tradingEngine.current.position.takeProfit.takeProfitStage.value === 'Manage Stage' && manageStage !== undefined) {
if (manageStage !== undefined) {
if (manageStage.managedTakeProfit !== undefined) {
phase = manageStage.managedTakeProfit.phases[tradingEngine.current.position.takeProfit.takeProfitPhase.value - 1]
}
@@ -513,7 +475,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
function calculateStopLossPosition() {
/*
The position of the Stop Loss (above or below the price) is needed in order to know
later if the price hit the Stop Loss or not at every Simulation cycle. When we get
later if the price hit the Stop Loss or not at every Simulation candle. When we get
the first values of the simulation of the Stop Loss we check if it is above or below
the Position Rate, and we assign the values Above or Below to it.
*/
@@ -529,7 +491,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
function calculateTakeProfitPosition() {
/*
The position of the Take Profit (above or below the price) is needed in order to know
later if the price hit the Take Profit or not at every Simulation cycle. When we get
later if the price hit the Take Profit or not at every Simulation candle. When we get
the first values of the simulation of the Take Profits we check if it is above or below
the Position Rates, and we assign the values Above or Below to it.
*/
@@ -544,28 +506,13 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
function checkStopPhasesEvents() {
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
let openStage = strategy.openStage
let manageStage = strategy.manageStage
let parentNode
let phaseIndex
let phase
let stopLoss
let stage
if (tradingEngine.current.position.stopLoss.stopLossStage.value === 'Open Stage' && openStage !== undefined) {
stage = openStage
if (openStage.initialDefinition !== undefined) {
if (openStage.initialDefinition.initialStopLoss !== undefined) {
parentNode = openStage.initialDefinition
phaseIndex = tradingEngine.current.position.stopLoss.stopLossPhase.value
stopLoss = openStage.initialDefinition.initialStopLoss
phase = stopLoss.phases[phaseIndex]
}
}
}
if (tradingEngine.current.position.stopLoss.stopLossStage.value === 'Manage Stage' && manageStage !== undefined) {
stage = manageStage
if (manageStage !== undefined) {
if (manageStage.managedStopLoss !== undefined) {
parentNode = manageStage
phaseIndex = tradingEngine.current.position.stopLoss.stopLossPhase.value - 1
@@ -596,9 +543,9 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
tradingSystem.highlights.push(phase.id)
tradingSystem.highlights.push(stopLoss.id)
tradingSystem.highlights.push(parentNode.id)
tradingSystem.highlights.push(stage.id)
tradingSystem.highlights.push(manageStage.id)
tradingPositionModule.updateStopLoss(tradingEngine.current.position.stopLoss.stopLossPhase.value + 1, 'Manage Stage')
tradingPositionModule.updateStopLoss(tradingEngine.current.position.stopLoss.stopLossPhase.value + 1)
announcementsModule.makeAnnoucements(nextPhaseEvent)
return // only one event can pass at the time
@@ -626,13 +573,13 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
tradingSystem.highlights.push(phase.id)
tradingSystem.highlights.push(stopLoss.id)
tradingSystem.highlights.push(parentNode.id)
tradingSystem.highlights.push(stage.id)
tradingSystem.highlights.push(manageStage.id)
let moveToPhase = moveToPhaseEvent.referenceParent
if (moveToPhase !== undefined) {
for (let q = 0; q < stopLoss.phases.length; q++) {
if (stopLoss.phases[q].id === moveToPhase.id) {
tradingPositionModule.updateStopLoss(q + 1, 'Manage Stage')
tradingPositionModule.updateStopLoss(q + 1)
}
}
} else {
@@ -657,22 +604,8 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
let phaseIndex
let phase
let takeProfit
let stage
if (tradingEngine.current.position.takeProfit.takeProfitStage.value === 'Open Stage' && openStage !== undefined) {
stage = openStage
if (openStage.initialDefinition !== undefined) {
if (openStage.initialDefinition.initialTakeProfit !== undefined) {
parentNode = openStage.initialDefinition
phaseIndex = tradingEngine.current.position.takeProfit.takeProfitPhase.value
takeProfit = openStage.initialDefinition.initialTakeProfit
phase = takeProfit.phases[phaseIndex]
}
}
}
if (tradingEngine.current.position.takeProfit.takeProfitStage.value === 'Manage Stage' && manageStage !== undefined) {
stage = manageStage
if (manageStage !== undefined) {
if (manageStage.managedTakeProfit !== undefined) {
parentNode = manageStage
phaseIndex = tradingEngine.current.position.takeProfit.takeProfitPhase.value - 1
@@ -703,9 +636,9 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
tradingSystem.highlights.push(phase.id)
tradingSystem.highlights.push(takeProfit.id)
tradingSystem.highlights.push(parentNode.id)
tradingSystem.highlights.push(stage.id)
tradingSystem.highlights.push(manageStage.id)
tradingPositionModule.updateTakeProfit(tradingEngine.current.position.takeProfit.takeProfitPhase.value + 1, 'Manage Stage')
tradingPositionModule.updateTakeProfit(tradingEngine.current.position.takeProfit.takeProfitPhase.value + 1)
announcementsModule.makeAnnoucements(nextPhaseEvent)
return // only one event can pass at the time
@@ -733,13 +666,13 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
tradingSystem.highlights.push(phase.id)
tradingSystem.highlights.push(takeProfit.id)
tradingSystem.highlights.push(parentNode.id)
tradingSystem.highlights.push(stage.id)
tradingSystem.highlights.push(manageStage.id)
let moveToPhase = moveToPhaseEvent.referenceParent
if (moveToPhase !== undefined) {
for (let q = 0; q < takeProfit.phases.length; q++) {
if (takeProfit.phases[q].id === moveToPhase.id) {
tradingPositionModule.updateTakeProfit(q + 1, 'Manage Stage')
tradingPositionModule.updateTakeProfit(q + 1)
}
}
} else {
@@ -809,105 +742,87 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
}
async function runCloseStage() {
/* Opening Status Procedure */
if (tradingEngine.current.strategyCloseStage.status.value === 'Opening') {
/*
This will happen only once, as soon as the Take Profit or Stop was hit.
We wil not be placing orders at this time because we do not know
the total filled size of the Open Stage. By skiping execution now
we allow the open stage to get a final value for sizeFilled that we can use.
*/
let stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].closeStage
/* Exit Position size and rate */
tradingSystem.evalFormulas(stageNode, 'Initial Targets')
tradingPositionModule.initialTargets(stageNode)
runWhenStatusIsOpening()
await runWhenStatusIsOpen()
initializeStageTargetSize()
changeStageStatus('Close Stage', 'Open')
return
}
function runWhenStatusIsOpening() {
/* Opening Status Procedure */
if (tradingEngine.current.strategyCloseStage.status.value === 'Opening') {
/*
This will happen only once, as soon as the Take Profit or Stop was hit.
*/
let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].closeStage
/* Open Status Procedure */
if (tradingEngine.current.strategyCloseStage.status.value === 'Open') {
/*
This will happen as long as the Close Stage is Open.
*/
let stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].closeStage
let executionNode = stageNode.closeExecution
/* Exit Position size and rate */
tradingSystem.evalFormulas(tradingSystemStage, 'Initial Targets')
tradingPositionModule.initialTargets(tradingSystemStage, tradingEngine.current.strategyCloseStage)
tradingSystem.evalConditions(stageNode, 'Close Execution')
tradingSystem.evalFormulas(stageNode, 'Close Execution')
await tradingExecutionModule.runExecution(
executionNode,
tradingEngine.current.strategyCloseStage
)
/*
The Open is finished when the placedSize reaches the targetSize in any of the
stage assets, and the fillSize + feesPaid reaches the placedSize also in any
of the stage Assets.
This can happens at any time when we update the sizeFilled and the feesPaid values
when we see at the exchange that orders were filled.
*/
if (
(
tradingEngine.current.strategyCloseStage.stageBaseAsset.sizePlaced >=
tradingEngine.current.strategyCloseStage.stageBaseAsset.targetSize
||
tradingEngine.current.strategyCloseStage.stageQuotedAsset.sizePlaced >=
tradingEngine.current.strategyCloseStage.stageQuotedAsset.targetSize
)
&&
(
tradingEngine.current.strategyCloseStage.stageBaseAsset.sizeFilled.value +
tradingEngine.current.strategyCloseStage.stageBaseAsset.feesPaid.value >=
tradingEngine.current.strategyCloseStage.stageBaseAsset.sizePlaced.value
||
tradingEngine.current.strategyCloseStage.stageQuotedAsset.sizeFilled.value +
tradingEngine.current.strategyCloseStage.stageQuotedAsset.feesPaid.value >=
tradingEngine.current.strategyCloseStage.stageQuotedAsset.sizePlaced.value
)
) {
changeStageStatus('Close Stage', 'Closed', 'Size Placed Filled')
} else {
/* Check the Close Stage Event */
tradingSystem.evalConditions(stageNode, 'Close Stage Event')
if (checkStopStageEvent(stageNode) === true) {
changeStageStatus('Close Stage', 'Closing', 'Close Stage Event')
}
initializeStageTargetSize()
changeStageStatus('Close Stage', 'Open')
}
}
/* Exit Position Validation */
if (
async function runWhenStatusIsOpen() {
/*
The following code will run only when the Open Stage is closed.
The reason for that is that we need the final filled size of the Open Stage
to be known before we start placing orders at the Close Stage.
*/
if (
tradingEngine.current.strategyCloseStage.status.value === 'Open' &&
(
tradingEngine.current.strategyTriggerStage.status.value === 'Closed' ||
tradingEngine.current.strategyTriggerStage.status.value === tradingEngine.current.strategyTriggerStage.status.config.initialValue
tradingEngine.current.strategyOpenStage.status.value === 'Closed' ||
tradingEngine.current.strategyOpenStage.status.value == tradingEngine.current.strategyOpenStage.status.config.initialValue
)
&&
(
tradingEngine.current.strategyOpenStage.status.value === 'Closed' ||
tradingEngine.current.strategyOpenStage.status.value === tradingEngine.current.strategyOpenStage.status.config.initialValue
)
&&
(
tradingEngine.current.strategyManageStage.status.value === 'Closed' ||
tradingEngine.current.strategyManageStage.status.value === tradingEngine.current.strategyManageStage.status.config.initialValue
)
&&
(
tradingEngine.current.strategyCloseStage.status.value === 'Closed'
)
) {
) {
/*
This will happen as long as the Close Stage is Open.
*/
let tradingSystemStage = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].closeStage
let tradingEngineStage = tradingEngine.current.strategyCloseStage
let executionNode = tradingSystemStage.closeExecution
/* Exiting Everything now. */
exitPositionAndStrategy()
tradingSystem.evalConditions(tradingSystemStage, 'Close Execution')
tradingSystem.evalFormulas(tradingSystemStage, 'Close Execution')
await tradingExecutionModule.runExecution(
executionNode,
tradingEngine.current.strategyCloseStage
)
checkIfStageNeedsToBeClosed(tradingEngineStage, tradingSystemStage, 'Close Stage')
}
/*
Exit Position Validation: we need al the previous stages to be either closed
or at their initial default value. The last is becasue after Closed objects are
initialized to their defualts.
*/
if (
(
tradingEngine.current.strategyTriggerStage.status.value === 'Closed' ||
tradingEngine.current.strategyTriggerStage.status.value === tradingEngine.current.strategyTriggerStage.status.config.initialValue
)
&&
(
tradingEngine.current.strategyOpenStage.status.value === 'Closed' ||
tradingEngine.current.strategyOpenStage.status.value === tradingEngine.current.strategyOpenStage.status.config.initialValue
)
&&
(
tradingEngine.current.strategyManageStage.status.value === 'Closed' ||
tradingEngine.current.strategyManageStage.status.value === tradingEngine.current.strategyManageStage.status.config.initialValue
)
&&
(
tradingEngine.current.strategyCloseStage.status.value === 'Closed'
)
) {
/* Closing Everything now. */
closePositionAndStrategy()
}
}
function initializeStageTargetSize() {
@@ -921,8 +836,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
tradingEngine.current.strategyCloseStage.stageQuotedAsset.targetSize.value = global.PRECISE(tradingEngine.current.strategyCloseStage.stageQuotedAsset.targetSize.value, 10)
}
function exitPositionAndStrategy() {
function closePositionAndStrategy() {
/* Taking Position Snapshot */
if (bot.SESSION.type === 'Backtesting Session') {
if (sessionParameters.snapshots !== undefined) {
@@ -957,8 +871,53 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
}
}
function checkStopStageEvent(stage) {
function checkIfStageNeedsToBeClosed(tradingEngineStage, tradingSystemStage, stageName) {
/*
The Stage is closed when the placedSize reaches the targetSize, and the fillSize
+ feesPaid reaches the placedSize. This depends on how the user defined the stage:
either on Base Asset or Quoted Asset.
This can happens at any time when we update the sizeFilled and the feesPaid values
when we see at the exchange that orders were filled.
*/
switch (tradingEngineStage.stageDefinedIn.value) {
case 'Base Asset': {
if (
tradingEngineStage.stageBaseAsset.sizeFilled.value +
tradingEngineStage.stageBaseAsset.feesPaid.value >=
tradingEngineStage.stageBaseAsset.targetSize.value
) {
positionFilled()
} else {
checkCloseStageEvent(tradingSystemStage)
}
break
}
case 'Quoted Asset': {
if (
tradingEngineStage.stageQuotedAsset.sizeFilled.value +
tradingEngineStage.stageQuotedAsset.feesPaid.value >=
tradingEngineStage.stageQuotedAsset.targetSize.value
) {
positionFilled()
} else {
checkCloseStageEvent(tradingSystemStage)
}
break
}
}
function positionFilled() {
changeStageStatus(stageName, 'Closed', 'Position Size Filled')
}
function checkCloseStageEvent(tradingSystemStage) {
/* Check the Close Stage Event */
tradingSystem.evalConditions(tradingSystemStage, 'Close Stage Event')
if (checkStopStageEvent(tradingSystemStage) === true) {
changeStageStatus(stageName, 'Closing', 'Close Stage Event')
}
}
}
function checkStopStageEvent(stage) {
/* Check the Close Stage Event. */
let stopStageEvent = stage.stopStageEvent
if (stopStageEvent !== undefined) {
@@ -1017,33 +976,33 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
function openStage(stage) {
/* Recording the opening at the Trading Engine Data Structure */
stage.begin.value = tradingEngine.current.episode.candle.begin.value
stage.begin.value = tradingEngine.current.episode.cycle.begin.value
stage.beginRate.value = tradingEngine.current.episode.candle.close.value
stage.end.value = tradingEngine.current.episode.candle.end.value
stage.end.value = tradingEngine.current.episode.cycle.end.value
}
function closeStage(stage) {
/* Recording the closing at the Trading Engine Data Structure */
stage.end.value = tradingEngine.current.episode.candle.end.value
stage.end.value = tradingEngine.current.episode.cycle.end.value
stage.endRate.value = tradingEngine.current.episode.candle.close.value
}
}
function updateEnds() {
if (tradingEngine.current.strategyTriggerStage.status.value === 'Open') {
tradingEngine.current.strategyTriggerStage.end.value = tradingEngine.current.episode.candle.end.value
tradingEngine.current.strategyTriggerStage.end.value = tradingEngine.current.episode.cycle.end.value
tradingEngine.current.strategyTriggerStage.endRate.value = tradingEngine.current.episode.candle.close.value
}
if (tradingEngine.current.strategyOpenStage.status.value === 'Open') {
tradingEngine.current.strategyOpenStage.end.value = tradingEngine.current.episode.candle.end.value
tradingEngine.current.strategyOpenStage.end.value = tradingEngine.current.episode.cycle.end.value
tradingEngine.current.strategyOpenStage.endRate.value = tradingEngine.current.episode.candle.close.value
}
if (tradingEngine.current.strategyManageStage.status.value === 'Open') {
tradingEngine.current.strategyManageStage.end.value = tradingEngine.current.episode.candle.end.value
tradingEngine.current.strategyManageStage.end.value = tradingEngine.current.episode.cycle.end.value
tradingEngine.current.strategyManageStage.endRate.value = tradingEngine.current.episode.candle.close.value
}
if (tradingEngine.current.strategyCloseStage.status.value === 'Open') {
tradingEngine.current.strategyCloseStage.end.value = tradingEngine.current.episode.candle.end.value
tradingEngine.current.strategyCloseStage.end.value = tradingEngine.current.episode.cycle.end.value
tradingEngine.current.strategyCloseStage.endRate.value = tradingEngine.current.episode.candle.close.value
}
}
@@ -5,6 +5,7 @@ exports.newTradingStrategy = function newTradingStrategy(bot, logger, tradingEng
const MODULE_NAME = 'Trading Strategy'
let thisObject = {
mantain: mantain,
reset: reset,
openStrategy: openStrategy,
closeStrategy: closeStrategy,
initialize: initialize,
@@ -24,16 +25,19 @@ exports.newTradingStrategy = function newTradingStrategy(bot, logger, tradingEng
}
function mantain() {
resetTradingEngineDataStructure()
updateCounters()
updateEnds()
}
function reset() {
resetTradingEngineDataStructure()
}
function openStrategy(index, situationName, strategyName) {
tradingEngine.current.strategy.status.value = 'Open'
tradingEngine.current.strategy.serialNumber.value = tradingEngine.current.episode.episodeCounters.strategies.value
tradingEngine.current.strategy.identifier.value = global.UNIQUE_ID()
tradingEngine.current.strategy.begin.value = tradingEngine.current.episode.candle.begin.value
tradingEngine.current.strategy.begin.value = tradingEngine.current.episode.candle.end.value
tradingEngine.current.strategy.end.value = tradingEngine.current.episode.candle.end.value
tradingEngine.current.strategy.beginRate.value = tradingEngine.current.episode.candle.min.value
+12 -11
View File
@@ -6,6 +6,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
const MODULE_NAME = 'Trading System'
let thisObject = {
mantain: mantain,
reset: reset,
run: run,
updateChart: updateChart,
initialize: initialize,
@@ -97,19 +98,19 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
}
function mantain() {
reset()
tradingStagesModule.mantain()
}
function reset() {
/* This function helps reset data structures at every cycle of the simulation loop/=. */
tradingSystem.highlights = []
tradingSystem.errors = []
tradingSystem.values = []
tradingSystem.status = []
tradingSystem.progress = []
tradingSystem.running = []
tradingSystem.announcements = []
}
function reset() {
tradingStagesModule.reset()
tradingSystem.highlights = []
tradingSystem.errors = []
tradingSystem.values = []
tradingSystem.status = []
tradingSystem.progress = []
tradingSystem.running = []
tradingSystem.announcements = []
}
function updateChart(pChart) {
+14
View File
@@ -160,6 +160,20 @@
finalDatetime: (new Date()).valueOf()
}
}
} else {
/* Check that we received valid dates */
if(isNaN(new Date(bot.SESSION.parameters.timeRange.config.initialDatetime)).valueOf()) {
let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date."
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
bot.sessionError(bot.SESSION.parameters, errorMessage)
return false
}
if(isNaN(new Date(bot.SESSION.parameters.timeRange.config.finalDatetime)).valueOf()) {
let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date."
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
bot.sessionError(bot.SESSION.parameters, errorMessage)
return false
}
}
/* Session Type Forced Values */
+2
View File
@@ -1,3 +1,5 @@
/* Callbacks default responses. */
global.DEFAULT_OK_RESPONSE = {
result: "Ok",