Running again

This commit is contained in:
Luis Fernando Molina committed 2020-08-02 20:33:41 +02:00
1 parent 0b581fe837
commit 84e927e420
10 files changed
+545 -368

No files matched your search

+1 -11
View File
@@ -77,17 +77,7 @@
let type // CCXT: a string literal type of order, ccxt currently unifies market and limit orders only
let side // CCXT: a string literal for the direction of your order, buy or sell
let symbol = bot.market.baseAsset + '/' + bot.market.quotedAsset // CCXT: a string literal symbol of the market you wish to trade on, like BTC/USD, ZEC/ETH, DOGE/DASH, etc
let amount // CCXT: how much of currency you want to trade
/*
We need at the amount a value denominated in Base Asset, if we do not
have it, then we convert the value we have in Quoteed Asset.
*/
if (tradingEngineOrder.orderBaseAsset.size.value > 0) {
amount = tradingEngineOrder.orderBaseAsset.size.value
} else {
amount = tradingEngineOrder.orderQuotedAsset.size.value / tradingEngineOrder.rate.value
}
let amount = tradingEngineOrder.orderBaseAsset.size.value // CCXT: how much of currency you want to trade, in Base Asset.
switch (tradingSystemOrder.type) {
case 'Market Buy Order': {
+175 -135
View File
@@ -53,16 +53,16 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
) {
/* Trading Stage Validations */
if (tradingEngineStage.stageBaseAsset === undefined) { continue }
if (tradingEngineStage.stageBaseAsset.size === undefined) { continue }
if (tradingEngineStage.stageBaseAsset.sizeFilled === undefined) { continue }
if (tradingEngineStage.stageBaseAsset.amountReceived === undefined) { continue }
if (tradingEngineStage.stageBaseAsset.feesPaid === undefined) { continue }
if (tradingEngineStage.stageQuotedAsset === undefined) { continue }
if (tradingEngineStage.stageQuotedAsset.size === undefined) { continue }
if (tradingEngineStage.stageQuotedAsset.sizeFilled === undefined) { continue }
if (tradingEngineStage.stageQuotedAsset.amountReceived === undefined) { continue }
if (tradingEngineStage.stageQuotedAsset.feesPaid === undefined) { continue }
if (tradingEngineStage.stageBaseAsset === undefined) { return }
if (tradingEngineStage.stageBaseAsset.size === undefined) { return }
if (tradingEngineStage.stageBaseAsset.sizeFilled === undefined) { return }
if (tradingEngineStage.stageBaseAsset.amountReceived === undefined) { return }
if (tradingEngineStage.stageBaseAsset.feesPaid === undefined) { return }
if (tradingEngineStage.stageQuotedAsset === undefined) { return }
if (tradingEngineStage.stageQuotedAsset.size === undefined) { return }
if (tradingEngineStage.stageQuotedAsset.sizeFilled === undefined) { return }
if (tradingEngineStage.stageQuotedAsset.amountReceived === undefined) { return }
if (tradingEngineStage.stageQuotedAsset.feesPaid === undefined) { return }
/*
The user choice of asset to define the size of the position,
@@ -217,11 +217,11 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
/* Check Size: We are not going to create Orders which size is equal or less to zero. */
if (traingEngineOrderAsset.size.value <= 0) { return }
/* Place Order at the Exchange */
/* Place Order at the Exchange, if needed. */
let result = await createOrderAtExchange(tradingSystemOrder, tradingEngineOrder)
if (result !== true) { return }
/* Update Stage Counters */
/* Update Stage Size */
tradingEngineStage.stageBaseAsset.size.value = tradingEngineStage.stageBaseAsset.size.value + tradingEngineOrder.orderBaseAsset.size.value
tradingEngineStage.stageBaseAsset.size.value = global.PRECISE(tradingEngineStage.stageBaseAsset.size.value, 10)
tradingEngineStage.stageQuotedAsset.size.value = tradingEngineStage.stageQuotedAsset.size.value + tradingEngineOrder.orderQuotedAsset.size.value
@@ -392,18 +392,24 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
/* Filter by what is defined at the Strategy */
if (tradingSystemOrder.simulatedExchangeEvents === undefined) { return }
let previousSizeFilled = tradingEngineOrderAsset.sizeFilled.value
let previousPercentageFilled = tradingEngineOrder.orderStatistics.percentageFilled.value
let previousAmountReceived = tradingEngineOrder.orderStatistics.amountReceived.value
let previousFeesPaid = tradingEngineOrder.orderStatistics.feesPaid.value
let previousBaseAssetSizeFilled = tradingEngineOrder.orderBaseAsset.sizeFilled.value
let previousQuotedAssetSizeFilled = tradingEngineOrder.orderQuotedAsset.sizeFilled.value
let previousBaseAssetFeesPaid = tradingEngineOrder.orderBaseAsset.feesPaid.value
let previousQuotedAssetFeesPaid = tradingEngineOrder.orderQuotedAsset.feesPaid.value
actualRateSimulation()
feesPaidSimulation()
orderFillingSimulation()
percentageFilledSimulation()
sizeFilledSimulation()
amountReceivedSimulation()
doTheAccounting(tradingSystemOrder, tradingEngineOrder, previousSizeFilled, previousPercentageFilled, previousFeesPaid)
doTheAccounting(
tradingSystemOrder,
tradingEngineOrder,
previousBaseAssetSizeFilled,
previousQuotedAssetSizeFilled,
previousBaseAssetFeesPaid,
previousQuotedAssetFeesPaid
)
/* If the Stage is Closing and this order is still open, we need to cancel it now */
if (stageIsClosing === true && tradingEngineOrder.status.value !== 'Closed') {
@@ -462,8 +468,21 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
/* Based on the Trading System Definition */
if (tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid !== undefined) {
if (tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid.config.percentage !== undefined) {
if (tradingEngineOrder.orderStatistics.feesPaid.value === tradingEngineOrder.orderStatistics.feesPaid.config.initialValue) {
tradingEngineOrder.orderStatistics.feesPaid.value = tradingEngineOrder.size.value * tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid.config.percentage / 100
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
}
}
@@ -474,19 +493,36 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
/* Fees are simulated based on the Session Paremeters */
switch (tradingEngineOrder.type) {
case 'Market Order': {
tradingEngineOrder.orderStatistics.feesPaid.value = tradingEngineOrder.size.value * bot.SESSION.parameters.feeStructure.config.taker / 100
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.orderStatistics.feesPaid.value = tradingEngineOrder.size.value * bot.SESSION.parameters.feeStructure.config.maker / 100
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.orderStatistics.feesPaid.value = global.PRECISE(tradingEngineOrder.orderStatistics.feesPaid.value, 10)
tradingEngineOrder.orderBaseAsset.feesPaid.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.feesPaid.value, 10)
tradingEngineOrder.orderQuotedAsset.feesPaid.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.feesPaid.value, 10)
}
function orderFillingSimulation() {
function percentageFilledSimulation() {
/* Order Filling Simulation */
if (tradingSystemOrder.simulatedExchangeEvents.simulatedPartialFill !== undefined) {
if (tradingSystemOrder.simulatedExchangeEvents.simulatedPartialFill.config.fillProbability !== undefined) {
@@ -515,34 +551,16 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
function sizeFilledSimulation() {
/* Size Filled */
tradingEngineOrder.orderStatistics.sizeFilled.value = tradingEngineOrder.size.value * tradingEngineOrder.orderStatistics.percentageFilled.value / 100
tradingEngineOrder.orderStatistics.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderStatistics.sizeFilled.value, 10)
}
tradingEngineOrder.orderBaseAsset.sizeFilled.value =
tradingEngineOrder.orderBaseAsset.size.value *
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
function amountReceivedSimulation() {
/* Amount Received */
let calculatedBasedOnOrderDefinition = false
tradingEngineOrder.orderQuotedAsset.sizeFilled.value =
tradingEngineOrder.orderQuotedAsset.size.value *
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
/* Based on the Order Definition */
if (tradingSystemOrder.simulatedExchangeEvents !== undefined) {
if (tradingSystemOrder.simulatedExchangeEvents.simulatedActualRate !== undefined) {
if (tradingSystemOrder.simulatedExchangeEvents.simulatedActualRate.formula !== undefined) {
let simulatedActualRate = tradingSystem.formulas.get(tradingSystemOrder.simulatedExchangeEvents.simulatedActualRate.formula.id)
if (simulatedActualRate !== undefined) {
tradingEngineOrder.orderStatistics.amountReceived.value = tradingEngineOrder.orderStatistics.sizeFilled.value * simulatedActualRate
tradingEngineOrder.orderStatistics.amountReceived.value = global.PRECISE(tradingEngineOrder.orderStatistics.amountReceived.value, 10)
calculatedBasedOnOrderDefinition = true
}
}
}
}
/* Based on Candle Close Value */
if (calculatedBasedOnOrderDefinition === false) {
let simulatedActualRate = tradingEngine.current.candle.close.value
tradingEngineOrder.orderStatistics.amountReceived.value = tradingEngineOrder.orderStatistics.sizeFilled.value * simulatedActualRate
tradingEngineOrder.orderStatistics.amountReceived.value = global.PRECISE(tradingEngineOrder.orderStatistics.amountReceived.value, 10)
}
tradingEngineOrder.orderBaseAsset.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.sizeFilled.value, 10)
tradingEngineOrder.orderQuotedAsset.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.sizeFilled.value, 10)
}
}
@@ -776,24 +794,57 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
tradingEngine.current.balance.quotedAsset.value = global.PRECISE(tradingEngine.current.balance.quotedAsset.value, 10)
}
function simulateCancelOrder(tradingSystemOrder, tradingEngineOrder, exitType) {
}
/* Filter by Session Type */
switch (bot.SESSION.type) {
case 'Backtesting Session': {
break
}
case 'Live Trading Session': {
return
}
case 'Fordward Testing Session': {
return
}
case 'Paper Trading Session': {
break
}
function simulateCancelOrder(tradingSystemOrder, tradingEngineOrder, exitType) {
/* Filter by Session Type */
switch (bot.SESSION.type) {
case 'Backtesting Session': {
break
}
case 'Live Trading Session': {
return
}
case 'Fordward Testing Session': {
return
}
case 'Paper Trading Session': {
break
}
}
/* Close this Order */
tradingEngineOrder.status.value = 'Closed'
tradingEngineOrder.exitType.value = exitType
/* Initialize this */
tradingEngine.current.distanceToEvent.closeOrder.value = 1
recalculateStageSize(tradingEngineOrder)
}
async function exchangeCancelOrder(tradingSystemOrder, tradingEngineOrder, exitType) {
/* Filter by Session Type */
switch (bot.SESSION.type) {
case 'Backtesting Session': {
return
}
case 'Live Trading Session': {
break
}
case 'Fordward Testing Session': {
break
}
case 'Paper Trading Session': {
return
}
}
/* Check if we can cancel the order at the Exchange. */
let result = await exchangeAPIModule.cancelOrder(tradingSystemOrder, tradingEngineOrder)
if (result === true) {
/* Close this Order */
tradingEngineOrder.status.value = 'Closed'
tradingEngineOrder.exitType.value = exitType
@@ -801,85 +852,74 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
/* Initialize this */
tradingEngine.current.distanceToEvent.closeOrder.value = 1
/* Since the order was cancelled, we remove the unfilled amount of the order from here */
let unfilledPercentage = 100 - tradingEngineOrder.orderStatistics.percentageFilled.value
let unfilledSize = tradingEngineOrder.size.value * unfilledPercentage / 100
stageOrdersSize.value = stageOrdersSize.value - unfilledSize
stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10)
/*
Perhaps the order was filled a bit more between the last time we checked and when it was cancelled.
To sync our accounting, we need to check the order one last time and if it changed, fix it.
*/
let order = await exchangeAPIModule.getOrder(tradingSystemOrder, tradingEngineOrder)
if (order === undefined) { return }
syncWithExchange(tradingSystemOrder, tradingEngineOrder, order)
recalculateStageSize()
}
}
async function exchangeCancelOrder(tradingSystemOrder, tradingEngineOrder, exitType) {
function recalculateStageSize(tradingEngineOrder) {
/*
Since the order is Cancelled, we need to adjust the stage size. Remember that the Stage Size
accumulates for each asset, the order size placed at the exchange. A cancelation means that
only the part filled can be considered placed, so we need to substract from the stage size
the remainder. To achieve this with the information we currently have, we are going first
to unaccount the order size, and the account only the sizeFilled + the feesPaid.
*/
tradingEngineStage.stageBaseAsset.size.value =
tradingEngineStage.stageBaseAsset.size.value -
tradingEngineOrder.orderBaseAsset.size.value
tradingEngineStage.stageQuotedAsset.size.value =
tradingEngineStage.stageQuotedAsset.size.value -
tradingEngineOrder.orderQuotedAsset.size.value
/* Filter by Session Type */
switch (bot.SESSION.type) {
case 'Backtesting Session': {
return
tradingEngineStage.stageBaseAsset.size.value =
tradingEngineStage.stageBaseAsset.size.value +
tradingEngineOrder.orderBaseAsset.sizeFilled.value +
tradingEngineOrder.orderBaseAsset.feesPaid.value
tradingEngineStage.stageQuotedAsset.size.value =
tradingEngineStage.stageQuotedAsset.size.value +
tradingEngineOrder.orderQuotedAsset.sizeFilled.value +
tradingEngineOrder.orderQuotedAsset.feesPaid.value
tradingEngineStage.stageBaseAsset.size.value = global.PRECISE(tradingEngineStage.stageBaseAsset.size.value, 10)
tradingEngineStage.stageQuotedAsset.size.value = global.PRECISE(tradingEngineStage.stageQuotedAsset.size.value, 10)
}
function checkOrderEvent(event, order, executionAlgorithm, executionNode) {
if (event !== undefined) {
for (let k = 0; k < event.situations.length; k++) {
let situation = event.situations[k]
let passed
if (situation.conditions.length > 0) {
passed = true
}
case 'Live Trading Session': {
break
}
case 'Fordward Testing Session': {
break
}
case 'Paper Trading Session': {
return
}
}
/* Check if we can cancel the order at the Exchange. */
let result = await exchangeAPIModule.cancelOrder(tradingSystemOrder, tradingEngineOrder)
if (result === true) {
/* Close this Order */
tradingEngineOrder.status.value = 'Closed'
tradingEngineOrder.exitType.value = exitType
passed = tradingSystem.checkConditions(situation, passed)
/* Initialize this */
tradingEngine.current.distanceToEvent.closeOrder.value = 1
tradingSystem.values.push([situation.id, passed])
if (passed) {
tradingSystem.highlights.push(situation.id)
tradingSystem.highlights.push(event.id)
tradingSystem.highlights.push(order.id)
tradingSystem.highlights.push(executionAlgorithm.id)
tradingSystem.highlights.push(executionNode.id)
/* Since the order was cancelled, we remove the unfilled amount of the order from here */
let unfilledPercentage = 100 - tradingEngineOrder.orderStatistics.percentageFilled.value
let unfilledSize = tradingEngineOrder.size.value * unfilledPercentage / 100
stageOrdersSize.value = stageOrdersSize.value - unfilledSize
stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10)
/*
Perhaps the order was filled a bit more between the last time we checked and when it was cancelled.
To sync our accounting, we need to check the order one last time and if it changed, fix it.
*/
let order = await exchangeAPIModule.getOrder(tradingSystemOrder, tradingEngineOrder)
if (order === undefined) { return }
syncWithExchange(tradingSystemOrder, tradingEngineOrder, order)
}
}
function checkOrderEvent(event, order, executionAlgorithm, executionNode) {
if (event !== undefined) {
for (let k = 0; k < event.situations.length; k++) {
let situation = event.situations[k]
let passed
if (situation.conditions.length > 0) {
passed = true
}
passed = tradingSystem.checkConditions(situation, passed)
tradingSystem.values.push([situation.id, passed])
if (passed) {
tradingSystem.highlights.push(situation.id)
tradingSystem.highlights.push(event.id)
tradingSystem.highlights.push(order.id)
tradingSystem.highlights.push(executionAlgorithm.id)
tradingSystem.highlights.push(executionNode.id)
announcementsModule.makeAnnoucements(event)
return situation.name // if the event is triggered, we return the name of the situation that passed
}
announcementsModule.makeAnnoucements(event)
return situation.name // if the event is triggered, we return the name of the situation that passed
}
}
}
}
}
}
+38 -101
View File
@@ -9,10 +9,6 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
closePosition: closePosition,
applyStopLossFormula: applyStopLossFormula,
applyTakeProfitFormula: applyTakeProfitFormula,
preventStopLossDistortion: preventStopLossDistortion,
applySlippageToStopLoss: applySlippageToStopLoss,
preventTakeProfitDistortion: preventTakeProfitDistortion,
applySlippageToTakeProfit: applySlippageToTakeProfit,
updateStopLoss: updateStopLoss,
updateTakeProfit: updateTakeProfit,
initializeSizeAndRate: initializeSizeAndRate,
@@ -20,23 +16,27 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
updateStatus: updateStatus,
updateCounters: updateCounters,
updateStatistics: updateStatistics,
updateResults: updateResults,
resetPosition: resetPosition,
initialize: initialize,
finalize: finalize
}
let tradingEngine
let tradingSystem
let sessionParameters
return thisObject
function initialize() {
tradingSystem = bot.simulationState.tradingSystem
tradingEngine = bot.simulationState.tradingEngine
sessionParameters = bot.SESSION.parameters
}
function finalize() {
tradingEngine = undefined
tradingSystem = undefined
sessionParameters = undefined
}
@@ -179,71 +179,6 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
}
}
function preventStopLossDistortion() {
/*
Hit Point Validation
This prevents misscalculations when a formula places the stop loss in this case way beyond the market price.
If we take the stop loss value at those situation would be a huge distortion of facts.
*/
if (bot.sessionAndMarketBaseAssetsAreEqual) {
if (tradingEngine.current.position.stopLoss.value < tradingEngine.current.candle.min.value) {
tradingEngine.current.position.stopLoss.value = tradingEngine.current.candle.min.value
}
} else {
if (tradingEngine.current.position.stopLoss.value > tradingEngine.current.candle.max.value) {
tradingEngine.current.position.stopLoss.value = tradingEngine.current.candle.max.value
}
}
}
function applySlippageToStopLoss() {
let slippedStopLoss = tradingEngine.current.position.stopLoss.value
/* Apply the Slippage */
let slippageAmount = slippedStopLoss * bot.SESSION.parameters.slippage.config.stopLoss / 100
if (bot.sessionAndMarketBaseAssetsAreEqual) {
slippedStopLoss = slippedStopLoss + slippageAmount
} else {
slippedStopLoss = slippedStopLoss - slippageAmount
}
tradingEngine.current.position.endRate.value = slippedStopLoss
}
function preventTakeProfitDistortion() {
/*
Hit Point Validation:
This prevents misscalculations when a formula places the take profit in this case way beyond the market price.
If we take the stop loss value at those situation would be a huge distortion of facts.
*/
if (bot.sessionAndMarketBaseAssetsAreEqual) {
if (tradingEngine.current.position.takeProfit.value > tradingEngine.current.candle.max.value) {
tradingEngine.current.position.takeProfit.value = tradingEngine.current.candle.max.value
}
} else {
if (tradingEngine.current.position.takeProfit.value < tradingEngine.current.candle.min.value) {
tradingEngine.current.position.takeProfit.value = tradingEngine.current.candle.min.value
}
}
}
function applySlippageToTakeProfit() {
let slippedTakeProfit = tradingEngine.current.position.takeProfit.value
/* Apply the Slippage */
let slippageAmount = slippedTakeProfit * bot.SESSION.parameters.slippage.config.takeProfit / 100
if (bot.sessionAndMarketBaseAssetsAreEqual) {
slippedTakeProfit = slippedTakeProfit + slippageAmount
} else {
slippedTakeProfit = slippedTakeProfit - slippageAmount
}
tradingEngine.current.position.endRate.value = slippedTakeProfit
}
function updateEnds() {
if (tradingEngine.current.position.status.value === 'Open') {
tradingEngine.current.position.end.value = tradingEngine.current.candle.end.value
@@ -264,45 +199,47 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
function updateStatistics() {
if (bot.sessionAndMarketBaseAssetsAreEqual) {
/* Profit Loss Calculation */
tradingEngine.current.position.positionStatistics.profitLoss.value =
tradingEngine.current.balance.baseAsset.value -
tradingEngine.previous.balance.baseAsset.value +
tradingEngine.current.balance.quotedAsset.value / tradingEngine.current.position.endRate.value -
tradingEngine.previous.balance.quotedAsset.value / tradingEngine.current.position.beginRate.value
/* ROI Calculation */
tradingEngine.current.position.positionStatistics.ROI.value =
tradingEngine.current.position.positionStatistics.profitLoss.value * 100 /
tradingEngine.current.position.size.value
} else {
/* Profit Loss Calculation */
tradingEngine.current.position.positionStatistics.profitLoss.value =
tradingEngine.current.balance.baseAsset.value * tradingEngine.current.position.endRate.value -
tradingEngine.previous.balance.baseAsset.value * tradingEngine.current.position.beginRate.value +
tradingEngine.current.balance.quotedAsset.value -
tradingEngine.previous.balance.quotedAsset.value
/* ROI Calculation */
tradingEngine.current.position.positionStatistics.ROI.value =
tradingEngine.current.position.positionStatistics.profitLoss.value * 100 /
(tradingEngine.current.position.size.value * tradingEngine.current.position.beginRate.value)
}
/* Days Calculation */
tradingEngine.current.position.positionStatistics.days.value = tradingEngine.current.position.positionCounters.periods.value *
tradingEngine.current.position.positionStatistics.days.value =
tradingEngine.current.position.positionCounters.periods.value *
sessionParameters.timeFrame.config.value / global.ONE_DAY_IN_MILISECONDS
tradingEngine.current.position.positionStatistics.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionStatistics.profitLoss.value, 10)
tradingEngine.current.position.positionStatistics.ROI.value = global.PRECISE(tradingEngine.current.position.positionStatistics.ROI.value, 10)
tradingEngine.current.position.positionStatistics.days.value = global.PRECISE(tradingEngine.current.position.positionStatistics.days.value, 10)
}
function updateResults() {
/* Profit Loss Calculation */
tradingEngine.current.position.positionBaseAsset.profitLoss.value =
tradingEngine.current.balance.baseAsset.value -
tradingEngine.previous.balance.baseAsset.value
tradingEngine.current.position.positionQuotedAsset.profitLoss.value =
tradingEngine.current.balance.quotedAsset.value -
tradingEngine.previous.balance.quotedAsset.value
tradingEngine.current.position.positionBaseAsset.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionBaseAsset.profitLoss.value, 10)
/* ROI Calculation */
tradingEngine.current.position.positionBaseAsset.ROI.value =
tradingEngine.current.position.positionBaseAsset.profitLoss.value * 100 /
tradingEngine.current.position.positionBaseAsset.size.value
tradingEngine.current.position.positionQuotedAsset.ROI.value =
tradingEngine.current.position.positionQuotedAsset.profitLoss.value * 100 /
tradingEngine.current.position.positionQuotedAsset.size.value
tradingEngine.current.position.positionBaseAsset.ROI.value = global.PRECISE(tradingEngine.current.position.positionBaseAsset.ROI.value, 10)
/* Hit Fail Calculation */
if (tradingEngine.current.position.positionStatistics.ROI.value > 0) {
tradingEngine.current.position.positionStatistics.hitFail.value = 'HIT'
if (tradingEngine.current.position.positionBaseAsset.ROI.value > 0) {
tradingEngine.current.position.positionBaseAsset.hitFail.value = 'HIT'
} else {
tradingEngine.current.position.positionStatistics.hitFail.value = 'FAIL'
tradingEngine.current.position.positionBaseAsset.hitFail.value = 'FAIL'
}
if (tradingEngine.current.position.positionQuotedAsset.ROI.value > 0) {
tradingEngine.current.position.positionQuotedAsset.hitFail.value = 'HIT'
} else {
tradingEngine.current.position.positionQuotedAsset.hitFail.value = 'FAIL'
}
}
}
@@ -133,7 +133,12 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
We will use the codeName of the Record Property to match it with
the any of the properties of the Root Node to get the Target Node.
*/
let targetNode = propertyRootNode[recordProperty.config.codeName]
let targetNode
try {
targetNode = propertyRootNode[recordProperty.config.codeName]
} catch (err) {
console.log(err.stack)
}
/*
If the codeName of the Record Property can not match the name of the property at
the target node, the user can explicitly specify the property name at the configuration,
@@ -167,7 +172,11 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
value = targetNode.value
if (recordProperty.config.decimals !== undefined) {
value = Number(value.toFixed(recordProperty.config.decimals))
try {
value = Number(value.toFixed(recordProperty.config.decimals))
} catch (err) {
console.log(err.stack)
}
}
} else {
/*
@@ -62,9 +62,6 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
let heartBeatDate
let previousHeartBeatDate
/* This determines where we are standing */
bot.sessionAndMarketBaseAssetsAreEqual = (sessionParameters.sessionBaseAsset.referenceParent.referenceParent.config.codeName === bot.market.baseAsset)
initializeLoop()
function initializeLoop() {
@@ -363,36 +360,49 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
if (
tradingEngine.current.strategy.index.value === tradingEngine.current.strategy.index.config.initialValue
) {
/*
First thing to do is to check if we are below the minimum balance, or above the maximun balance.
If we are, we are not gooing to trigger on again.
/*
We will perform this check only when we are not inside a position,
because there the balances have shifted from their resting position.
*/
let minimumBalance
let maximumBalance
let balance
if (bot.sessionAndMarketBaseAssetsAreEqual) {
balance = tradingEngine.current.balance.baseAsset.value
minimumBalance = sessionParameters.sessionBaseAsset.config.minimumBalance
maximumBalance = sessionParameters.sessionBaseAsset.config.maximumBalance
} else {
balance = tradingEngine.current.balance.quotedAsset.value
minimumBalance = sessionParameters.sessionQuotedAsset.config.minimumBalance
maximumBalance = sessionParameters.sessionQuotedAsset.config.maximumBalance
let stopRunningDate = (new Date(tradingEngine.current.candle.begin.value)).toLocaleString()
if (sessionParameters.sessionBaseAsset.config.minimumBalance !== undefined) {
if (tradingEngine.current.balance.baseAsset.value <= sessionParameters.sessionBaseAsset.config.minimumBalance) {
const errorMessage = 'Min Balance reached @ ' + stopRunningDate
tradingSystem.errors.push([tradingSystem.id, errorMessage])
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> checkMinimunAndMaximunBalance -> ' + errorMessage) }
return false
}
}
let stopRunningDate = new Date(tradingEngine.current.candle.begin.value)
if (balance <= minimumBalance) {
tradingSystem.error = 'Min Balance @ ' + stopRunningDate.toLocaleString()
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> checkMinimunAndMaximunBalance -> ' + tradingSystem.error) }
return false
if (sessionParameters.sessionBaseAsset.config.maximumBalance !== undefined) {
if (tradingEngine.current.balance.baseAsset.value >= sessionParameters.sessionBaseAsset.config.maximumBalance) {
const errorMessage = 'Max Balance reached @ ' + stopRunningDate
tradingSystem.errors.push([tradingSystem.id, errorMessage])
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> checkMinimunAndMaximunBalance -> ' + errorMessage) }
return false
}
}
if (balance >= maximumBalance) {
tradingSystem.error = 'Max Balance @ ' + stopRunningDate.toLocaleString()
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> checkMinimunAndMaximunBalance -> ' + tradingSystem.error) }
return false
if (sessionParameters.sessionQuotedAsset.config.minimumBalance !== undefined) {
if (tradingEngine.current.balance.quotedAsset.value <= sessionParameters.sessionQuotedAsset.config.minimumBalance) {
const errorMessage = 'Min Balance reached @ ' + stopRunningDate
tradingSystem.errors.push([tradingSystem.id, errorMessage])
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> checkMinimunAndMaximunBalance -> ' + errorMessage) }
return false
}
}
if (sessionParameters.sessionQuotedAsset.config.maximumBalance !== undefined) {
if (tradingEngine.current.balance.quotedAsset.value >= sessionParameters.sessionQuotedAsset.config.maximumBalance) {
const errorMessage = 'Max Balance reached @ ' + stopRunningDate
tradingSystem.errors.push([tradingSystem.id, errorMessage])
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[WARN] runSimulation -> checkMinimunAndMaximunBalance -> ' + errorMessage) }
return false
}
}
}
return true
}
+183 -41
View File
@@ -549,7 +549,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
false,
tradingEngine.current.position.positionBaseAsset.size, // Stage Size Limit
tradingEngine.current.position.positionQuotedAsset.size, // Stage Size Limit
tradingEngine.current.position.strategyOpenStage
tradingEngine.current.strategyOpenStage
)
/* From here on, the state is officialy Open */
@@ -576,15 +576,15 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
false,
tradingEngine.current.position.positionBaseAsset.size, // Stage Size Limit
tradingEngine.current.position.positionQuotedAsset.size, // Stage Size Limit
tradingEngine.current.position.strategyOpenStage
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 filledSize value when we see
This can happens at any time when we update the sizeFilled value when we see
at the exchange that orders were filled.
*/
if (
tradingEngine.current.strategyOpenStage.stageBaseAsset.filledSize.value +
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled.value +
tradingEngine.current.strategyOpenStage.stageBaseAsset.feesPaid.value >=
tradingEngine.current.position.positionBaseAsset.size.value * 0.999) {
tradingStrategyModule.updateStageStatus('Open Stage', 'Closed', 'Position Size Filled')
@@ -607,7 +607,10 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
let executionNode = stageNode.openExecution
/* Check if there are unfilled orders */
if (tradingEngine.current.position.openStageOrdersSize.value !== tradingEngine.current.position.openStageFilledSize.value) {
if (
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled.value +
tradingEngine.current.strategyOpenStage.stageBaseAsset.feesPaid.value <
tradingEngine.current.position.positionBaseAsset.size.value * 0.999) {
/* There are unfilled orders, we will check if they were executed, and cancel the ones that were not. */
evalConditions(stageNode, 'Open Execution')
@@ -619,18 +622,18 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
true,
tradingEngine.current.position.positionBaseAsset.size, // Stage Size Limit
tradingEngine.current.position.positionQuotedAsset.size, // Stage Size Limit
tradingEngine.current.position.strategyOpenStage
tradingEngine.current.strategyOpenStage
)
}
/*
The Closing is finished when the fillSize + feesPaid reaches the ordersSize.
This can happens either because we update the filledSize value when we see
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.
*/
if (
tradingEngine.current.strategyOpenStage.stageBaseAsset.filledSize.value +
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled.value +
tradingEngine.current.strategyOpenStage.stageBaseAsset.feesPaid.value >=
tradingEngine.current.position.positionBaseAsset.size.value * 0.999) {
tradingStrategyModule.updateStageStatus('Open Stage', 'Closed')
@@ -664,15 +667,49 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
/* Stop Loss Management */
checkStopPhasesEvents()
calculateStopLoss()
calculateStopLossPosition()
/* Take Profit Management */
checkTakeProfitPhaseEvents()
calculateTakeProfit()
calculateTakeProfitPosition()
/* Checking if Stop or Take Profit were hit */
checkStopLossOrTakeProfitWasHit()
}
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
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.
*/
if (tradingEngine.current.position.stopLoss.stopLossPosition.value === tradingEngine.current.position.stopLoss.stopLossPosition.config.initialValue) {
if (tradingEngine.current.position.stopLoss.value > tradingEngine.current.position.rate) {
tradingEngine.current.position.stopLoss.stopLossPosition.value = 'Above'
} else {
tradingEngine.current.position.stopLoss.stopLossPosition.value = 'Below'
}
}
}
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
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.
*/
if (tradingEngine.current.position.takeProfit.takeProfitPosition.value === tradingEngine.current.position.takeProfit.takeProfitPosition.config.initialValue) {
if (tradingEngine.current.position.takeProfit.value > tradingEngine.current.position.rate) {
tradingEngine.current.position.takeProfit.takeProfitPosition.value = 'Above'
} else {
tradingEngine.current.position.takeProfit.takeProfitPosition.value = 'Below'
}
}
}
function checkStopPhasesEvents() {
let strategy = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value]
let openStage = strategy.openStage
@@ -897,13 +934,17 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
/* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */
if (
(bot.sessionAndMarketBaseAssetsAreEqual && tradingEngine.current.candle.max.value >= tradingEngine.current.position.stopLoss.value) ||
(!bot.sessionAndMarketBaseAssetsAreEqual && tradingEngine.current.candle.min.value <= tradingEngine.current.position.stopLoss.value)
(
tradingEngine.current.position.stopLoss.stopLossPosition.value === 'Above' &&
tradingEngine.current.candle.max.value >= tradingEngine.current.position.stopLoss.value
) ||
(
tradingEngine.current.position.stopLoss.stopLossPosition.value === 'Below' &&
tradingEngine.current.candle.min.value <= tradingEngine.current.position.stopLoss.value
)
) {
logger.write(MODULE_NAME, '[INFO] checkStopLossOrTakeProfitWasHit -> Stop Loss was hit.')
tradingPositionModule.preventStopLossDistortion()
tradingPositionModule.applySlippageToStopLoss()
tradingPositionModule.closingPosition('Stop Loss')
tradingStrategyModule.updateStageStatus('Close Stage', 'Opening')
tradingStrategyModule.updateStageStatus('Manage Stage', 'Closed')
@@ -913,13 +954,17 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
/* Take Profit condition: Here we verify if the Take Profit was hit or not. */
if (
(bot.sessionAndMarketBaseAssetsAreEqual && tradingEngine.current.candle.min.value <= tradingEngine.current.position.takeProfit.value) ||
(!bot.sessionAndMarketBaseAssetsAreEqual && tradingEngine.current.candle.max.value >= tradingEngine.current.position.takeProfit.value)
(
tradingEngine.current.position.takeProfit.takeProfitPosition.value === 'Below' &&
tradingEngine.current.candle.min.value <= tradingEngine.current.position.takeProfit.value
) ||
(
tradingEngine.current.position.takeProfit.takeProfitPosition.value === 'Above' &&
tradingEngine.current.candle.max.value >= tradingEngine.current.position.takeProfit.value
)
) {
logger.write(MODULE_NAME, '[INFO] checkStopLossOrTakeProfitWasHit -> Take Profit was hit.')
tradingPositionModule.preventTakeProfitDistortion()
tradingPositionModule.applySlippageToTakeProfit()
tradingPositionModule.closingPosition('Take Profit')
tradingStrategyModule.updateStageStatus('Close Stage', 'Opening')
tradingStrategyModule.updateStageStatus('Manage Stage', 'Closed')
@@ -938,7 +983,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
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 filledSize that we can use.
we allow the open stage to get a final value for sizeFilled that we can use.
*/
tradingStrategyModule.updateStageStatus('Close Stage', 'Open')
return
@@ -961,18 +1006,18 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
false,
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled, // Stage Size Limit
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizeFilled, // Stage Size Limit
tradingEngine.current.position.strategyCloseStage
tradingEngine.current.strategyCloseStage
)
/*
The Close Stage is finished when the fillSize + feesPaid reaches the Open Fill Size.
This can happens at any time when we update the filledSize value when we see
This can happens at any time when we update the sizeFilled value when we see
at the exchange that orders were filled.
*/
if (
tradingEngine.current.strategyCloseStage.stageBaseAsset.filledSize.value +
tradingEngine.current.strategyCloseStage.stageBaseAsset.sizeFilled.value +
tradingEngine.current.strategyCloseStage.stageBaseAsset.feesPaid.value >=
tradingEngine.current.strategyOpenStage.stageBaseAsset.filledSize.value * 0.999) {
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled.value * 0.999) {
tradingStrategyModule.updateStageStatus('Close Stage', 'Closed', 'Open Stage fillSize Filled')
} else {
/* Check the Close Stage Event */
@@ -997,28 +1042,12 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
function exitPositionAndStrategy() {
/* Needed for Episode Statistics */
/* Position Statistics & Results */
tradingPositionModule.updateStatistics()
tradingPositionModule.updateResults()
/* Recalculating Episode Counters */
if (tradingEngine.current.position.positionStatistics.profitLoss.value > 0) {
tradingEngine.episode.episodeCounters.hits.value++
} else {
tradingEngine.episode.episodeCounters.fails.value++
}
/* Recalculating Episode Statistics */
if (bot.sessionAndMarketBaseAssetsAreEqual) {
tradingEngine.episode.episodeStatistics.profitLoss.value = tradingEngine.current.balance.baseAsset.value - sessionParameters.sessionBaseAsset.config.initialBalance
tradingEngine.episode.episodeStatistics.ROI.value = (sessionParameters.sessionBaseAsset.config.initialBalance + tradingEngine.episode.episodeStatistics.profitLoss.value) / sessionParameters.sessionBaseAsset.config.initialBalance - 1
tradingEngine.episode.episodeStatistics.hitRatio.value = tradingEngine.episode.episodeCounters.hits.value / tradingEngine.episode.episodeCounters.positions.value
tradingEngine.episode.episodeStatistics.anualizedRateOfReturn.value = tradingEngine.episode.episodeStatistics.ROI.value / tradingEngine.episode.episodeStatistics.days.value * 365
} else {
tradingEngine.episode.episodeStatistics.profitLoss.value = tradingEngine.current.balance.quotedAsset.value - sessionParameters.sessionQuotedAsset.config.initialBalance
tradingEngine.episode.episodeStatistics.ROI.value = (sessionParameters.sessionQuotedAsset.config.initialBalance + tradingEngine.episode.episodeStatistics.profitLoss.value) / sessionParameters.sessionQuotedAsset.config.initialBalance - 1
tradingEngine.episode.episodeStatistics.hitRatio.value = tradingEngine.episode.episodeCounters.hits.value / tradingEngine.episode.episodeCounters.positions.value
tradingEngine.episode.episodeStatistics.anualizedRateOfReturn.value = tradingEngine.episode.episodeStatistics.ROI.value / tradingEngine.episode.episodeStatistics.days.value * 365
}
updatingEpisodeAssets()
updatingEpisodeStatistics()
/* Taking Position Snapshot */
if (bot.SESSION.type === 'Backtesting Session') {
@@ -1047,6 +1076,119 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
/* Distance to Events Updates */
tradingEngine.current.distanceToEvent.closePosition.value = 1
tradingEngine.current.distanceToEvent.triggerOff.value = 1
function updatingEpisodeAssets() {
/* Updating Hits & Fails */
if (tradingEngine.current.position.positionBaseAsset.profitLoss.value > 0) {
tradingEngine.episode.episodeBaseAsset.hits.value++
} else {
tradingEngine.episode.episodeBaseAsset.fails.value++
}
if (tradingEngine.current.position.positionQuotedAsset.profitLoss.value > 0) {
tradingEngine.episode.episodeQuotedAsset.hits.value++
} else {
tradingEngine.episode.episodeQuotedAsset.fails.value++
}
/* Updating Profit Loss */
tradingEngine.episode.episodeBaseAsset.profitLoss.value =
tradingEngine.current.balance.baseAsset.value -
sessionParameters.sessionBaseAsset.config.initialBalance
tradingEngine.episode.episodeQuotedAsset.profitLoss.value =
tradingEngine.current.balance.quotedAsset.value -
sessionParameters.sessionQuotedAsset.config.initialBalance
tradingEngine.episode.episodeBaseAsset.profitLoss.value = global.PRECISE(tradingEngine.episode.episodeBaseAsset.profitLoss.value, 10)
tradingEngine.episode.episodeQuotedAsset.profitLoss.value = global.PRECISE(tradingEngine.episode.episodeQuotedAsset.profitLoss.value, 10)
/* Updating ROI */
tradingEngine.episode.episodeBaseAsset.ROI.value =
(sessionParameters.sessionBaseAsset.config.initialBalance + tradingEngine.episode.episodeBaseAsset.profitLoss.value) /
sessionParameters.sessionBaseAsset.config.initialBalance - 1
tradingEngine.episode.episodeQuotedAsset.ROI.value =
(sessionParameters.sessionQuotedAsset.config.initialBalance + tradingEngine.episode.episodeQuotedAsset.profitLoss.value) /
sessionParameters.sessionQuotedAsset.config.initialBalance - 1
tradingEngine.episode.episodeBaseAsset.ROI.value = global.PRECISE(tradingEngine.episode.episodeBaseAsset.ROI.value, 10)
tradingEngine.episode.episodeQuotedAsset.ROI.value = global.PRECISE(tradingEngine.episode.episodeQuotedAsset.ROI.value, 10)
/* Updating Hit Ratio */
tradingEngine.episode.episodeBaseAsset.hitRatio.value =
tradingEngine.episode.episodeBaseAsset.hits.value /
tradingEngine.episode.episodeCounters.positions.value
tradingEngine.episode.episodeQuotedAsset.hitRatio.value =
tradingEngine.episode.episodeQuotedAsset.hits.value /
tradingEngine.episode.episodeCounters.positions.value
tradingEngine.episode.episodeBaseAsset.hitRatio.value = global.PRECISE(tradingEngine.episode.episodeBaseAsset.hitRatio.value, 10)
tradingEngine.episode.episodeQuotedAsset.hitRatio.value = global.PRECISE(tradingEngine.episode.episodeQuotedAsset.hitRatio.value, 10)
/* Updating Anualized Rate Of Return */
tradingEngine.episode.episodeBaseAsset.anualizedRateOfReturn.value =
tradingEngine.episode.episodeBaseAsset.ROI.value /
tradingEngine.episode.episodeStatistics.days.value * 365
tradingEngine.episode.episodeQuotedAsset.anualizedRateOfReturn.value =
tradingEngine.episode.episodeQuotedAsset.ROI.value /
tradingEngine.episode.episodeStatistics.days.value * 365
tradingEngine.episode.episodeBaseAsset.anualizedRateOfReturn.value = global.PRECISE(tradingEngine.episode.episodeBaseAsset.anualizedRateOfReturn.value, 10)
tradingEngine.episode.episodeQuotedAsset.anualizedRateOfReturn.value = global.PRECISE(tradingEngine.episode.episodeQuotedAsset.anualizedRateOfReturn.value, 10)
/* Updating Hit or Fail */
if (tradingEngine.episode.episodeBaseAsset.profitLoss.value > 0) {
tradingEngine.episode.episodeBaseAsset.hitFail.value = 'Hit'
} else {
tradingEngine.episode.episodeBaseAsset.hitFail.value = 'Fail'
}
if (tradingEngine.episode.episodeQuotedAsset.profitLoss.value > 0) {
tradingEngine.episode.episodeQuotedAsset.hitFail.value = 'Hit'
} else {
tradingEngine.episode.episodeQuotedAsset.hitFail.value = 'Fail'
}
}
function updatingEpisodeStatistics() {
/* Updating Profit Loss */
tradingEngine.episode.episodeStatistics.profitLoss.value =
tradingEngine.episode.episodeBaseAsset.profitLoss.value * tradingEngine.current.candle.close.value +
tradingEngine.episode.episodeQuotedAsset.profitLoss.value
tradingEngine.episode.episodeStatistics.profitLoss.value = global.PRECISE(tradingEngine.episode.episodeStatistics.profitLoss.value, 10)
/* Updating ROI */
tradingEngine.episode.episodeStatistics.ROI.value =
(
sessionParameters.sessionBaseAsset.config.initialBalance * tradingEngine.current.candle.close.value +
tradingEngine.episode.episodeBaseAsset.profitLoss.value * tradingEngine.current.candle.close.value +
sessionParameters.sessionQuotedAsset.config.initialBalance +
tradingEngine.episode.episodeQuotedAsset.profitLoss.value
) / (
sessionParameters.sessionBaseAsset.config.initialBalance * tradingEngine.current.candle.close.value +
sessionParameters.sessionQuotedAsset.config.initialBalance
) - 1
tradingEngine.episode.episodeStatistics.ROI.value = global.PRECISE(tradingEngine.episode.episodeStatistics.ROI.value, 10)
/* Updating Anualized Rate Of Return */
tradingEngine.episode.episodeStatistics.anualizedRateOfReturn.value =
tradingEngine.episode.episodeStatistics.ROI.value /
tradingEngine.episode.episodeStatistics.days.value * 365
tradingEngine.episode.episodeStatistics.anualizedRateOfReturn.value = global.PRECISE(tradingEngine.episode.episodeStatistics.anualizedRateOfReturn.value, 10)
/* Updating Hit or Fail */
if (tradingEngine.episode.episodeStatistics.profitLoss.value > 0) {
tradingEngine.episode.episodeStatistics.hitFail.value = 'Hit'
} else {
tradingEngine.episode.episodeStatistics.hitFail.value = 'Fail'
}
}
}
}
-12
View File
@@ -229,12 +229,6 @@
bot.sessionError(bot.SESSION.parameters.sessionBaseAsset, errorMessage)
return false
}
if (bot.SESSION.parameters.sessionBaseAsset.config.minimumBalance === undefined) {
bot.SESSION.parameters.sessionBaseAsset.config.minimumBalance = 0
}
if (bot.SESSION.parameters.sessionBaseAsset.config.maximumBalance === undefined) {
bot.SESSION.parameters.sessionBaseAsset.config.maximumBalance = Number.MAX_SAFE_INTEGER
}
/* Session Quoted Asset */
if (bot.SESSION.parameters.sessionQuotedAsset === undefined) {
@@ -249,12 +243,6 @@
bot.sessionError(bot.SESSION.parameters.sessionQuotedAsset, errorMessage)
return false
}
if (bot.SESSION.parameters.sessionQuotedAsset.config.minimumBalance === undefined) {
bot.SESSION.parameters.sessionQuotedAsset.config.minimumBalance = 0
}
if (bot.SESSION.parameters.sessionQuotedAsset.config.maximumBalance === undefined) {
bot.SESSION.parameters.sessionQuotedAsset.config.maximumBalance = Number.MAX_SAFE_INTEGER
}
/* Slippage */
if (bot.SESSION.parameters.slippage === undefined) { // if the Slippage is missing we create a default one.