diff --git a/LowFrequencyTrading/TradingExecution.js b/LowFrequencyTrading/TradingExecution.js index 33e0706d8..ca32989fb 100644 --- a/LowFrequencyTrading/TradingExecution.js +++ b/LowFrequencyTrading/TradingExecution.js @@ -80,7 +80,7 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE let tradingSystemOrder = orders[i] /* Trading System Validations */ - if (tradingSystemOrder.config.positionSizePercentage === undefined) { badDefinitionUnhandledException(undefined, 'tradingSystemOrder.config.positionSizePercentage === undefined', tradingSystemOrder) } + if (tradingSystemOrder.config.percentageOfAlgorithmSize === undefined) { badDefinitionUnhandledException(undefined, 'tradingSystemOrder.config.percentageOfAlgorithmSize === undefined', tradingSystemOrder) } if (tradingSystemOrder.referenceParent === undefined) { badDefinitionUnhandledException(undefined, 'tradingSystemOrder.referenceParent === undefined', tradingSystemOrder) } let tradingEngineOrder = tradingEngineModule.getNodeById(tradingSystemOrder.referenceParent.id) @@ -204,11 +204,13 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE tradingEngineOrder.situationName.value = situationName function calculateOrderRate() { - /* Order Rate Calculation */ - tradingEngineOrder.rate.value = tradingEngine.current.position.rate.value // By default this is the order rate. - if (tradingSystemOrder.positionRate !== undefined) { - if (tradingSystemOrder.positionRate.formula !== undefined) { - tradingEngineOrder.rate.value = tradingSystem.formulas.get(tradingSystemOrder.positionRate.formula.id) + /* By default this is the order rate and it is the rate that applies to Market Orders */ + tradingEngineOrder.rate.value = tradingEngine.current.candle.close.value + + /* Optional Rate Definition */ + if (tradingSystemOrder.orderRate !== undefined) { + if (tradingSystemOrder.orderRate.formula !== undefined) { + tradingEngineOrder.rate.value = tradingSystem.formulas.get(tradingSystemOrder.orderRate.formula.id) if (tradingEngineOrder.rate.value === undefined) { badDefinitionUnhandledException(undefined, 'tradingEngineOrder.rate.value === undefined', tradingEngineOrder) } if (isNaN(tradingEngineOrder.rate.value) === true) { badDefinitionUnhandledException(undefined, 'isNaN(tradingEngineOrder.rate.value) === true', tradingEngineOrder) } @@ -220,45 +222,24 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE } function calculateOrderSize() { - /* - If the position size was defined in Base Asset, then - the algorithm needs to define its size also in Base Asset. - The same if it was deined in Quoted Asset. - */ - let sizeFormula - if (tradingEngine.current.position.positionBaseAsset.size.value > 0) { - /* Position was defined in Base Asset */ - if (executionAlgorithm.sizeInBaseAsset === undefined) { badDefinitionUnhandledException(undefined, 'executionAlgorithm.sizeInBaseAsset === undefined', executionAlgorithm) } - if (executionAlgorithm.sizeInBaseAsset.formula === undefined) { badDefinitionUnhandledException(undefined, 'executionAlgorithm.sizeInBaseAsset.formula === undefined', executionAlgorithm.sizeInBaseAsset) } - sizeFormula = executionAlgorithm.sizeInBaseAsset.formula - } else { - /* Position was defined in Quoted Asset */ - if (executionAlgorithm.sizeInQuotedAsset === undefined) { badDefinitionUnhandledException(undefined, 'executionAlgorithm.sizeInQuotedAsset === undefined', executionAlgorithm) } - if (executionAlgorithm.sizeInQuotedAsset.formula === undefined) { badDefinitionUnhandledException(undefined, 'executionAlgorithm.sizeInQuotedAsset.formula === undefined', executionAlgorithm.sizeInBaseAsset) } - sizeFormula = executionAlgorithm.sizeInQuotedAsset.formula - } + /* Validate that this config exists */ + if (executionAlgorithm.config.percentageOfStageTargetSize === undefined) { badDefinitionUnhandledException(undefined, 'executionAlgorithm.config.percentageOfStageTargetSize === undefined', executionAlgorithm) } + if (isNaN(executionAlgorithm.config.percentageOfStageTargetSize) === true) { badDefinitionUnhandledException(undefined, 'isNaN(executionAlgorithm.config.percentageOfStageTargetSize) === true', executionAlgorithm) } - /* Order Size Calculation */ - let algorithmSize = tradingSystem.formulas.get(sizeFormula.id) - if (algorithmSize === undefined) { badDefinitionUnhandledException(undefined, 'algorithmSize === undefined', sizeFormula) } - if (isNaN(algorithmSize) === true) { badDefinitionUnhandledException(undefined, 'isNaN(algorithmSize) === true', sizeFormula) } + let algorithmSizeInBaseAsset = tradingEngineStage.stageBaseAsset.targetSize.value * executionAlgorithm.config.percentageOfStageTargetSize / 100 + let algorithmSizeInQuotedAsset = tradingEngineStage.stageQuotedAsset.targetSize.value * executionAlgorithm.config.percentageOfStageTargetSize / 100 /* Validate that this config exists */ - if (tradingSystemOrder.config.positionSizePercentage === undefined) { badDefinitionUnhandledException(undefined, 'tradingSystemOrder.config.positionSizePercentage === undefined', executionAlgorithm) } + 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) } - if (tradingEngine.current.position.positionBaseAsset.size.value > 0) { - /* Position was defined in Base Asset */ - tradingEngineOrder.orderBaseAsset.size.value = algorithmSize * tradingSystemOrder.config.positionSizePercentage / 100 - tradingEngineOrder.orderQuotedAsset.size.value = tradingEngineOrder.orderBaseAsset.size.value * tradingEngineOrder.rate.value - } else { - /* Position was defined in Quoted Asset */ - tradingEngineOrder.orderQuotedAsset.size.value = algorithmSize * tradingSystemOrder.config.positionSizePercentage / 100 - tradingEngineOrder.orderBaseAsset.size.value = tradingEngineOrder.orderQuotedAsset.size.value / tradingEngineOrder.rate.value - } - tradingEngineOrder.orderBaseAsset.size.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.size.value, 10) - tradingEngineOrder.orderBaseAsset.size.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.size.value, 10) + /* Size in Base Asset */ + tradingEngineOrder.orderBaseAsset.size.value = algorithmSizeInBaseAsset * tradingSystemOrder.config.percentageOfAlgorithmSize / 100 - /* Check against the Stage Size Limit */ + /* 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 @@ -271,6 +252,9 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE ) { tradingEngineOrder.orderQuotedAsset.size.value = tradingEngineStage.stageQuotedAsset.targetSize.value - tradingEngineStage.stageQuotedAsset.sizePlaced.value } + + tradingEngineOrder.orderBaseAsset.size.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.size.value, 10) + tradingEngineOrder.orderQuotedAsset.size.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.size.value, 10) } async function createOrderAtExchange(tradingSystemOrder, tradingEngineOrder) { @@ -481,11 +465,11 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE function sizeFilledSimulation() { /* Size Filled */ tradingEngineOrder.orderBaseAsset.sizeFilled.value = - tradingEngineOrder.orderBaseAsset.size.value * + (tradingEngineOrder.orderBaseAsset.size.value - tradingEngineOrder.orderBaseAsset.feesPaid.value) * tradingEngineOrder.orderStatistics.percentageFilled.value / 100 tradingEngineOrder.orderQuotedAsset.sizeFilled.value = - tradingEngineOrder.orderQuotedAsset.size.value * + (tradingEngineOrder.orderQuotedAsset.size.value - tradingEngineOrder.orderQuotedAsset.feesPaid.value) * tradingEngineOrder.orderStatistics.percentageFilled.value / 100 tradingEngineOrder.orderBaseAsset.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.sizeFilled.value, 10) diff --git a/LowFrequencyTrading/TradingPosition.js b/LowFrequencyTrading/TradingPosition.js index 464087bb7..2b30fe00e 100644 --- a/LowFrequencyTrading/TradingPosition.js +++ b/LowFrequencyTrading/TradingPosition.js @@ -11,7 +11,7 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng applyTakeProfitFormula: applyTakeProfitFormula, updateStopLoss: updateStopLoss, updateTakeProfit: updateTakeProfit, - initializePositionSizeAndRate: initializePositionSizeAndRate, + initialTargets: initialTargets, updateEnds: updateEnds, updateStatus: updateStatus, updateCounters: updateCounters, @@ -100,93 +100,122 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng tradingEngine.current.position.takeProfit.takeProfitStage.value = stage } - function initializePositionSizeAndRate() { + function initialTargets(stageNode) { - setPositionSize() - setPositionRate() + if (stageNode.initialTargets === undefined) { + const message = 'Stage without Initial Targets node. Add one please.' + badDefinitionUnhandledException(undefined, message, stageNode) + } - tradingEngine.current.position.beginRate.value = tradingEngine.current.position.rate.value + setTargetRate() + setTargetSize() - function setPositionSize() { - let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value] - - /* Basic Validation */ - if ( - strategy.openStage.initialDefinition.positionSizeInBaseAsset !== undefined && - strategy.openStage.initialDefinition.positionSizeInQuotedAsset !== undefined - ) { - const errorText = 'Only Position Size In Base Asset or Position Size In Quoted Asset is allowed. Remove one of them please.' - tradingSystem.errors.push([strategy.openStage.initialDefinition.id, errorText]) - throw (errorText) + function setTargetRate() { + if (stageNode.initialTargets.targetRate === undefined) { + const message = 'Target Rate Node not Found. Fix this please.' + badDefinitionUnhandledException(undefined, message, stageNode.initialTargets) + } + if (stageNode.initialTargets.targetRate.formula === undefined) { + const message = 'Formula of Target Rate Node not Found. Fix this please.' + badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetRate) } - /* Position In Base Asset */ - if (strategy.openStage.initialDefinition.positionSizeInBaseAsset !== undefined) { - if (strategy.openStage.initialDefinition.positionSizeInBaseAsset.formula !== undefined) { - let value = tradingSystem.formulas.get(strategy.openStage.initialDefinition.positionSizeInBaseAsset.formula.id) - if (value === undefined) { - const errorText = 'Position Size In Base Asset cannot be undefined. Fix this please.' - tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInBaseAsset.formula.id, errorText]) - throw (errorText) - } - if (value === undefined) { - const errorText = 'Position Size In Base Asset cannot be zero. Fix this please.' - tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInBaseAsset.formula.id, errorText]) - throw (errorText) - } - tradingEngine.current.position.positionBaseAsset.size.value = global.PRECISE(value, 10) - } else { - const errorText = 'You need to specify a Formula for this.' - tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInBaseAsset.id, errorText]) - throw (errorText) + let value = tradingSystem.formulas.get(stageNode.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) + } + if (isNaN(value)) { + const message = 'Target Rate must be a number. Fix this please.' + badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetRate.formula) + } + + switch (stageNode.type) { + case 'Open Stage': { + tradingEngine.current.position.entryTargetRate.value = global.PRECISE(value, 10) + break } - } - - /* Position In Quoted Asset */ - if (strategy.openStage.initialDefinition.positionSizeInQuotedAsset !== undefined) { - if (strategy.openStage.initialDefinition.positionSizeInQuotedAsset.formula !== undefined) { - let value = tradingSystem.formulas.get(strategy.openStage.initialDefinition.positionSizeInQuotedAsset.formula.id) - if (value === undefined) { - const errorText = 'Position Size In Quoted Asset cannot be undefined. Fix this please.' - tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInQuotedAsset.formula.id, errorText]) - throw (errorText) - } - if (value === undefined) { - const errorText = 'Position Size In Quoted Asset cannot be zero. Fix this please.' - tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInQuotedAsset.formula.id, errorText]) - throw (errorText) - } - tradingEngine.current.position.positionQuotedAsset.size.value = global.PRECISE(value, 10) - } else { - const errorText = 'You need to specify a Formula for this.' - tradingSystem.errors.push([strategy.openStage.initialDefinition.positionSizeInQuotedAsset.id, errorText]) - throw (errorText) + case 'Close Stage': { + tradingEngine.current.position.exitTargetRate.value = global.PRECISE(value, 10) + break } } } - function setPositionRate() { - let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value] - - if (strategy.openStage.initialDefinition.positionRate === undefined) { - const errorText = 'Position Rate Node not Found. Fix this please.' - tradingSystem.errors.push([strategy.openStage.initialDefinition.id, errorText]) - throw (errorText) - } - if (strategy.openStage.initialDefinition.positionRate.formula === undefined) { - const errorText = 'Formula of Position Rate Node not Found. Fix this please.' - tradingSystem.errors.push([strategy.openStage.initialDefinition.positionRate.id, errorText]) - throw (errorText) + function setTargetSize() { + /* Basic Validation */ + if ( + stageNode.initialTargets.targetSizeInBaseAsset !== undefined && + stageNode.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) } - let value = tradingSystem.formulas.get(strategy.openStage.initialDefinition.positionRate.formula.id) - if (value === undefined) { - const errorText = 'Position Rate can not be undefined. Fix this please.' - tradingSystem.errors.push([strategy.openStage.initialDefinition.positionRate.formula.id, errorText]) - throw (errorText) + /* 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 (value === undefined) { + const message = 'Target Size In Base Asset cannot be undefined. Fix this please.' + badDefinitionUnhandledException(undefined, message, stageNode.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) + } + + switch (stageNode.type) { + case 'Open Stage': { + tradingEngine.current.position.positionBaseAsset.entryTargetSize.value = global.PRECISE(value, 10) + tradingEngine.current.position.positionQuotedAsset.entryTargetSize.value = + global.PRECISE(value * tradingEngine.current.position.entryTargetRate.value, 10) + break + } + case 'Close Stage': { + tradingEngine.current.position.positionBaseAsset.exitTargetSize.value = global.PRECISE(value, 10) + tradingEngine.current.position.positionQuotedAsset.exitTargetSize.value = + global.PRECISE(value * tradingEngine.current.position.exitTargetRate.value, 10) + break + } + } + } else { + const message = 'You need to specify a Formula for this.' + badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetSizeInBaseAsset) + } } - tradingEngine.current.position.rate.value = value + /* 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 (value === undefined) { + const message = 'Target Size In Quoted Asset cannot be undefined. Fix this please.' + badDefinitionUnhandledException(undefined, message, stageNode.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) + } + switch (stageNode.type) { + case 'Open Stage': { + tradingEngine.current.position.positionQuotedAsset.entryTargetSize.value = global.PRECISE(value, 10) + tradingEngine.current.position.positionBaseAsset.entryTargetSize.value = + global.PRECISE(value / tradingEngine.current.position.entryTargetRate.value, 10) + break + } + case 'Close Stage': { + tradingEngine.current.position.positionQuotedAsset.exitTargetSize.value = global.PRECISE(value, 10) + tradingEngine.current.position.positionBaseAsset.exitTargetSize.value = + global.PRECISE(value / tradingEngine.current.position.exitTargetRate.value, 10) + break + } + } + } else { + const errorText = 'You need to specify a Formula for this.' + badDefinitionUnhandledException(undefined, message, stageNode.initialTargets.targetSizeInQuotedAsset.formula) + } + } } } @@ -233,11 +262,11 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng /* ROI Calculation */ tradingEngine.current.position.positionBaseAsset.ROI.value = tradingEngine.current.position.positionBaseAsset.profitLoss.value * 100 / - tradingEngine.current.position.positionBaseAsset.size.value + tradingEngine.current.position.positionBaseAsset.entryTargetSize.value tradingEngine.current.position.positionQuotedAsset.ROI.value = tradingEngine.current.position.positionQuotedAsset.profitLoss.value * 100 / - tradingEngine.current.position.positionQuotedAsset.size.value + tradingEngine.current.position.positionQuotedAsset.entryTargetSize.value tradingEngine.current.position.positionBaseAsset.ROI.value = global.PRECISE(tradingEngine.current.position.positionBaseAsset.ROI.value, 10) @@ -253,4 +282,17 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng tradingEngine.current.position.positionQuotedAsset.hitFail.value = 'FAIL' } } + + function badDefinitionUnhandledException(err, message, node) { + tradingSystem.errors.push([node.id, message]) + + logger.write(MODULE_NAME, "[ERROR] -> " + message); + logger.write(MODULE_NAME, "[ERROR] -> node.name = " + node.name); + logger.write(MODULE_NAME, "[ERROR] -> node.type = " + node.type); + logger.write(MODULE_NAME, "[ERROR] -> node.config = " + JSON.stringify(node.config)); + if (err !== undefined) { + logger.write(MODULE_NAME, "[ERROR] -> err.stack = " + err.stack); + } + throw 'It is not safe to continue with a Definition Error like this. Please fix the problem and try again.' + } } \ No newline at end of file diff --git a/LowFrequencyTrading/TradingStages.js b/LowFrequencyTrading/TradingStages.js index c565598e4..809d63361 100644 --- a/LowFrequencyTrading/TradingStages.js +++ b/LowFrequencyTrading/TradingStages.js @@ -343,9 +343,10 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM tradingEngine.previous.balance.baseAsset.value = tradingEngine.current.balance.baseAsset.value tradingEngine.previous.balance.quotedAsset.value = tradingEngine.current.balance.quotedAsset.value - /* Position size and rate */ - tradingPositionModule.initializePositionSizeAndRate() - initializeOpenStageSizeTarget() + /* 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') @@ -381,16 +382,36 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM tradingEngine.current.strategyOpenStage ) /* - The Open is finished when the fillSize + feesPaid reaches the Position Size. - This can happens at any time when we update the sizeFilled value when we see - at the exchange that orders were filled. + 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.sizeFilled.value + - tradingEngine.current.strategyOpenStage.stageBaseAsset.feesPaid.value >= - tradingEngine.current.strategyOpenStage.stageBaseAsset.sizePlaced.value * 0.999) { + ( + 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') - initializeCloseStageSizeTarget() } else { /* Check the Close Stage Event */ tradingSystem.evalConditions(stageNode, 'Close Stage Event') @@ -409,63 +430,51 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM let stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage let executionNode = stageNode.openExecution - /* Check if there are unfilled orders */ - if ( - tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled.value + - tradingEngine.current.strategyOpenStage.stageBaseAsset.feesPaid.value < - tradingEngine.current.strategyOpenStage.stageBaseAsset.sizePlaced.value * 0.999) { - /* There are unfilled orders, we will check if they were executed, and cancel the ones that were not. */ + /* + 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') - tradingSystem.evalConditions(stageNode, 'Open Execution') - tradingSystem.evalFormulas(stageNode, 'Open Execution') - - await tradingExecutionModule.runExecution( - executionNode, - true, - tradingEngine.current.strategyOpenStage - ) - } + await tradingExecutionModule.runExecution( + executionNode, + true, + tradingEngine.current.strategyOpenStage + ) /* 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. + 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 * 0.999) { + 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') - initializeCloseStageSizeTarget() } } - function initializeOpenStageSizeTarget() { + function initializeStageTargetSize() { /* Here we will transform the position size into targets for each asset of the stage. */ - if (tradingEngine.current.position.positionBaseAsset.size.value > 0) { - tradingEngine.current.strategyOpenStage.stageBaseAsset.targetSize.value = tradingEngine.current.position.positionBaseAsset.size.value - tradingEngine.current.strategyOpenStage.stageQuotedAsset.targetSize.value = - tradingEngine.current.position.positionBaseAsset.size.value * tradingEngine.current.position.rate.value - } else { - tradingEngine.current.strategyOpenStage.stageQuotedAsset.targetSize.value = tradingEngine.current.position.positionQuotedAsset.size.value - tradingEngine.current.strategyOpenStage.stageBaseAsset.targetSize.value = - tradingEngine.current.position.positionQuotedAsset.size.value / tradingEngine.current.position.rate.value - } + tradingEngine.current.strategyOpenStage.stageBaseAsset.targetSize.value = tradingEngine.current.position.positionBaseAsset.entryTargetSize.value + tradingEngine.current.strategyOpenStage.stageQuotedAsset.targetSize.value = tradingEngine.current.position.positionQuotedAsset.entryTargetSize.value tradingEngine.current.strategyOpenStage.stageBaseAsset.targetSize.value = global.PRECISE(tradingEngine.current.strategyOpenStage.stageBaseAsset.targetSize.value, 10) tradingEngine.current.strategyOpenStage.stageQuotedAsset.targetSize.value = global.PRECISE(tradingEngine.current.strategyOpenStage.stageQuotedAsset.targetSize.value, 10) } - - function initializeCloseStageSizeTarget() { - /* - Here we will move the size filled of the open stage to the size target of the close stage. - */ - tradingEngine.current.strategyCloseStage.stageBaseAsset.targetSize.value = tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled.value - tradingEngine.current.strategyCloseStage.stageQuotedAsset.targetSize.value = tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizeFilled.value - } } function runManageStage() { @@ -876,6 +885,12 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM 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. */ + + /* Exit Position size and rate */ + tradingSystem.evalFormulas(stageNode, 'Initial Targets') + tradingPositionModule.initialTargets(stageNode) + + initializeStageTargetSize() changeStageStatus('Close Stage', 'Open') return } @@ -898,14 +913,35 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM ) /* - The Close Stage is finished when the fillSize + feesPaid reaches the Open Fill Size. - This can happens at any time when we update the sizeFilled value when we see - at the exchange that orders were filled. + 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.sizeFilled.value + - tradingEngine.current.strategyCloseStage.stageBaseAsset.feesPaid.value >= - tradingEngine.current.strategyCloseStage.stageBaseAsset.sizePlaced.value * 0.999) { + ( + 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('Close Stage', 'Closed', 'Size Placed Filled') } else { /* Check the Close Stage Event */ @@ -942,6 +978,17 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM exitPositionAndStrategy() } + function initializeStageTargetSize() { + /* + Here we will transform the position size into targets for each asset of the stage. + */ + tradingEngine.current.strategyOpenStage.stageBaseAsset.targetSize.value = tradingEngine.current.position.positionBaseAsset.exitTargetSize.value + tradingEngine.current.strategyOpenStage.stageQuotedAsset.targetSize.value = tradingEngine.current.position.positionQuotedAsset.exitTargetSize.value + + tradingEngine.current.strategyOpenStage.stageBaseAsset.targetSize.value = global.PRECISE(tradingEngine.current.strategyOpenStage.stageBaseAsset.targetSize.value, 10) + tradingEngine.current.strategyOpenStage.stageQuotedAsset.targetSize.value = global.PRECISE(tradingEngine.current.strategyOpenStage.stageQuotedAsset.targetSize.value, 10) + } + function exitPositionAndStrategy() { /* Position Statistics & Results */ @@ -1187,15 +1234,18 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM function updateStatus() { if (tradingEngine.current.strategyTriggerStage.status.value === 'Closed') { - resetStage(tradingEngine.current.strategyTriggerStage) + resetStage(tradingEngine.current.strategyTriggerStage.status) } if (tradingEngine.current.strategyOpenStage.status.value === 'Closed') { - resetStage(tradingEngine.current.strategyOpenStage) + resetStage(tradingEngine.current.strategyOpenStage.status) } if (tradingEngine.current.strategyManageStage.status.value === 'Closed') { - resetStage(tradingEngine.current.strategyManageStage) + resetStage(tradingEngine.current.strategyManageStage.status) } if (tradingEngine.current.strategyCloseStage.status.value === 'Closed') { + resetStage(tradingEngine.current.strategyTriggerStage) + resetStage(tradingEngine.current.strategyOpenStage) + resetStage(tradingEngine.current.strategyManageStage) resetStage(tradingEngine.current.strategyCloseStage) } } diff --git a/LowFrequencyTrading/TradingSystem.js b/LowFrequencyTrading/TradingSystem.js index d371ae225..767973b32 100644 --- a/LowFrequencyTrading/TradingSystem.js +++ b/LowFrequencyTrading/TradingSystem.js @@ -118,17 +118,25 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM } async function run() { - /* Run the Trigger Stage */ - tradingStagesModule.runTriggerStage() + try { + /* Run the Trigger Stage */ + tradingStagesModule.runTriggerStage() - /* Run the Open Stage */ - await tradingStagesModule.runOpenStage() + /* Run the Open Stage */ + await tradingStagesModule.runOpenStage() - /* Run the Manage Stage */ - tradingStagesModule.runManageStage() + /* Run the Manage Stage */ + tradingStagesModule.runManageStage() - /* Run the Close Stage */ - await tradingStagesModule.runCloseStage() + /* Run the Close Stage */ + await tradingStagesModule.runCloseStage() + } catch (err) { + /* + If an error ocurred during execution, it was alreeady logged and + included at the errors array. That means we need to do nothing here, + just prevent the execution to be halted for not handling exceptions. + */ + } } function evalNode(node, evaluating, descendentOfNodeType, isDescendent) { diff --git a/server.js b/server.js index b9e30080f..1d5b92c6c 100644 --- a/server.js +++ b/server.js @@ -41,7 +41,7 @@ global.UNIQUE_ID = function () { } global.PRECISE = function (floatNumber, precision) { - return parseFloat(Number.parseFloat(floatNumber).toPrecision(precision)) + return this.parseFloat(floatNumber.toFixed(precision)) } process.on('uncaughtException', function (err) {