Improvements on Live Trading
This commit is contained in:
1 parent
b588db88dc
commit
092219ec47
12 files changed
+371
-259
No files matched your search
+1
-1
@@ -8646,7 +8646,7 @@
|
||||
"compatibleTypes": "->Execution Finished Event->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Process Definition->"
|
||||
"compatibleTypes": "->Process Definition->Trading Process Instance->"
|
||||
},
|
||||
"icon": "execution-started-event",
|
||||
"propertyNameAtParent": "executionStartedEvent"
|
||||
|
||||
@@ -110,6 +110,7 @@ function newUiObject() {
|
||||
|
||||
let errorMessage = ''
|
||||
let currentValue = 0
|
||||
let valueMinDecimals = undefined
|
||||
let currentPercentage = ''
|
||||
let currentStatus = ''
|
||||
let rightDragging = false
|
||||
@@ -745,10 +746,11 @@ function newUiObject() {
|
||||
hasError = false
|
||||
}
|
||||
|
||||
function setValue(value, counter) {
|
||||
function setValue(value, counter, minDecimals) {
|
||||
if (value !== undefined) {
|
||||
currentValue = value
|
||||
hasValue = true
|
||||
valueMinDecimals = minDecimals
|
||||
if (counter !== undefined) {
|
||||
valueCounter = counter
|
||||
} else {
|
||||
@@ -1438,7 +1440,7 @@ function newUiObject() {
|
||||
label = currentValue
|
||||
if (!isNaN(currentValue)) {
|
||||
if (currentValue.toFixed !== undefined) {
|
||||
label = dynamicDecimals(currentValue)
|
||||
label = dynamicDecimals(currentValue, valueMinDecimals)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,14 +95,14 @@ function newRecordValues() {
|
||||
pointing to the same property at the Target Node.
|
||||
*/
|
||||
if (property.config.childProperty !== undefined) {
|
||||
applyValue(targetNode[property.config.childProperty], value)
|
||||
applyValue(targetNode[property.config.childProperty], value, property.config.decimals)
|
||||
} else {
|
||||
applyValue(targetNode[property.config.codeName], value)
|
||||
applyValue(targetNode[property.config.codeName], value, property.config.decimals)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyValue(node, value) {
|
||||
function applyValue(node, value, minDecimals) {
|
||||
if (canvas.chartingSpace.visible !== true) { return }
|
||||
if (node === undefined) { return }
|
||||
if (node === undefined) { return }
|
||||
@@ -110,6 +110,6 @@ function newRecordValues() {
|
||||
if (node.payload.uiObject === undefined) { return }
|
||||
if (value === true) { value = 'true' }
|
||||
if (value === false) { value = 'false' }
|
||||
node.payload.uiObject.setValue(value, 1)
|
||||
node.payload.uiObject.setValue(value, 1, minDecimals)
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,15 @@ function dynamicDecimals(value, minDecimals) {
|
||||
if (minDecimals === undefined) {
|
||||
minDecimals = 0
|
||||
}
|
||||
let decimals = 2
|
||||
if (value < 1) { decimals = 4 }
|
||||
if (Math.abs(Math.trunc(value * 100)) < 1) { decimals = 6 }
|
||||
if (Math.abs(Math.trunc(value * 10000)) < 1) { decimals = 8 }
|
||||
if (Math.abs(Math.trunc(value * 1000000)) < 1) { decimals = 10 }
|
||||
if (Math.abs(Math.trunc(value * 100000000)) < 1) { decimals = 12 }
|
||||
let decimals = 0
|
||||
if (value < 1) { decimals = 2 }
|
||||
if (Math.abs(Math.trunc(value * 100)) < 1) { decimals = 4 }
|
||||
if (Math.abs(Math.trunc(value * 10000)) < 1) { decimals = 6 }
|
||||
if (Math.abs(Math.trunc(value * 1000000)) < 1) { decimals = 8 }
|
||||
if (Math.abs(Math.trunc(value * 100000000)) < 1) { decimals = 10 }
|
||||
if (Math.abs(Math.trunc(value * 10000000000)) < 1) { value = 0; decimals = 0 }
|
||||
if (Math.trunc(value) === value) { decimals = minDecimals }
|
||||
if (decimals < minDecimals) {decimals = minDecimals}
|
||||
|
||||
let returnValue = Number(value).toFixed(decimals)
|
||||
return returnValue
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"type":"Data Mine","name":"Masters-Trading","config":"{ \n\"codeName\": \"Masters-Trading\"\n}","sensorBots":[],"indicatorBots":[],"tradingBots":[{"type":"Trading Bot","name":"Low Frequency","config":"{\n\"codeName\": \"Low-Frequency\"\n}","processes":[{"type":"Process Definition","name":"Trading","config":"{\n \"codeName\": \"Trading\",\n \"sessionRunWaitTime\": 5000,\n \"retryWaitTime\": 10000,\n \"framework\": {\n \"name\": \"Low-Frequency-Trading-Process\"\n }\n }","processOutput":{"type":"Process Output","name":"New Process Output","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Episode Counters","id":"6fc3054e-5034-4fc7-bddf-02360e0a6acf","savedPayload":{"position":{"x":15126.709841795062,"y":14115.844903867037},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"db063d7b-db05-4bf6-941f-999e1ccb38fc"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Counters","id":"c3c2240f-514b-40de-825f-674037117d0b","savedPayload":{"position":{"x":15060.50960648652,"y":13958.543096746436},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"0764aaaf-d970-4f23-9df8-55fe5b7dd273"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Statistics","id":"1dfdfc0d-842f-4e63-a591-256ac8a06b0f","savedPayload":{"position":{"x":15000.170158581612,"y":13798.909615340754},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"fc9dc0f7-35e0-4548-bb91-f920825d694f"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Statistics","id":"39360c55-5ba8-413b-b0bd-cac3789ebf5f","savedPayload":{"position":{"x":14945.771166150153,"y":13637.156840896287},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"91953362-8751-4440-a898-21245cd47c15"}}},{"type":"Output Dataset","name":"Multi-Period-Market Current Candle","id":"ba614415-6e4f-4979-97a5-34c72a59e67c","savedPayload":{"position":{"x":14897.386505301713,"y":13473.814926987687},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"17fb41f5-61b5-4433-9a10-950ff8216a7e"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Current Candle","id":"1a2e3461-33e6-45b1-bcc1-c56a8c5d275c","savedPayload":{"position":{"x":14855.08212849534,"y":13309.762335468542},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"bbc9467d-28bf-432b-9e49-582d1bcabfb9"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Balances","id":"567e4dc9-4deb-41e4-9ac9-dde943fb91ba","savedPayload":{"position":{"x":14818.915848183393,"y":13144.277773603595},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"acddff59-b51b-4b45-b58f-71d4077755ee"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Balances","id":"e94b9bb3-9f0c-4550-94e1-09de444780a8","savedPayload":{"position":{"x":14788.936996026083,"y":12977.582492132336},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"213b8fe8-f772-41ea-a3f5-97867be555f7"}}},{"type":"Output Dataset","name":"Multi-Period-Market Distance To Event","id":"a30e7306-7be9-41b6-a465-558fdfe2a903","savedPayload":{"position":{"x":14765.186501949274,"y":12809.903263371778},"targetPosition":{"x":19338.91372893721,"y"Line truncated
|
||||
{"type":"Data Mine","name":"Masters-Trading","config":"{ \n\"codeName\": \"Masters-Trading\"\n}","sensorBots":[],"indicatorBots":[],"tradingBots":[{"type":"Trading Bot","name":"Low Frequency","config":"{\n\"codeName\": \"Low-Frequency\"\n}","processes":[{"type":"Process Definition","name":"Trading","config":"{\n \"codeName\": \"Trading\",\n \"sessionRunWaitTime\": 5000,\n \"retryWaitTime\": 10000,\n \"framework\": {\n \"name\": \"Low-Frequency-Trading-Process\"\n }\n }","processOutput":{"type":"Process Output","name":"New Process Output","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Episode Counters","id":"6fc3054e-5034-4fc7-bddf-02360e0a6acf","savedPayload":{"position":{"x":15126.709841795062,"y":14115.844903867037},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"db063d7b-db05-4bf6-941f-999e1ccb38fc"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Counters","id":"c3c2240f-514b-40de-825f-674037117d0b","savedPayload":{"position":{"x":15060.50960648652,"y":13958.543096746436},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"0764aaaf-d970-4f23-9df8-55fe5b7dd273"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Statistics","id":"1dfdfc0d-842f-4e63-a591-256ac8a06b0f","savedPayload":{"position":{"x":15000.170158581612,"y":13798.909615340754},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"fc9dc0f7-35e0-4548-bb91-f920825d694f"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Statistics","id":"39360c55-5ba8-413b-b0bd-cac3789ebf5f","savedPayload":{"position":{"x":14945.771166150153,"y":13637.156840896287},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"91953362-8751-4440-a898-21245cd47c15"}}},{"type":"Output Dataset","name":"Multi-Period-Market Current Candle","id":"ba614415-6e4f-4979-97a5-34c72a59e67c","savedPayload":{"position":{"x":14897.386505301713,"y":13473.814926987687},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"17fb41f5-61b5-4433-9a10-950ff8216a7e"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Current Candle","id":"1a2e3461-33e6-45b1-bcc1-c56a8c5d275c","savedPayload":{"position":{"x":14855.08212849534,"y":13309.762335468542},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"bbc9467d-28bf-432b-9e49-582d1bcabfb9"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Balances","id":"567e4dc9-4deb-41e4-9ac9-dde943fb91ba","savedPayload":{"position":{"x":14818.915848183393,"y":13144.277773603595},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"acddff59-b51b-4b45-b58f-71d4077755ee"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Balances","id":"e94b9bb3-9f0c-4550-94e1-09de444780a8","savedPayload":{"position":{"x":14788.936996026083,"y":12977.582492132336},"targetPosition":{"x":19338.91372893721,"y":12256.290080293493},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"213b8fe8-f772-41ea-a3f5-97867be555f7"}}},{"type":"Output Dataset","name":"Multi-Period-Market Distance To Event","id":"a30e7306-7be9-41b6-a465-558fdfe2a903","savedPayload":{"position":{"x":14765.186501949274,"y":12809.903263371778},"targetPosition":{"x":19338.91372893721,"y"Line truncated
|
||||
@@ -124,7 +124,7 @@
|
||||
return order.id
|
||||
} catch (err) {
|
||||
tradingSystem.errors.push([tradingSystemOrder.id, err.message])
|
||||
logError("getOrder -> Error = " + err.message);
|
||||
logError("createOrder -> Error = " + err.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,13 +133,13 @@
|
||||
let orderId = tradingEngineOrder.exchangeId.value
|
||||
|
||||
/* Basic Logging */
|
||||
logInfo("getOrder -> Entering function. orderId = " + orderId);
|
||||
logInfo("cancelOrder -> Entering function. orderId = " + orderId);
|
||||
|
||||
const symbol = bot.market.baseAsset + '/' + bot.market.quotedAsset
|
||||
|
||||
/* Basic Validations */
|
||||
if (exchange.has['fetchOrder'] === false) {
|
||||
logError("getOrder -> Exchange does not support fetchOrder command.");
|
||||
logError("cancelOrder -> Exchange does not support fetchOrder command.");
|
||||
return
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
return true
|
||||
} catch (err) {
|
||||
tradingSystem.errors.push([tradingSystemOrder.id, err.message])
|
||||
logError("getOrder -> Error = " + err.message);
|
||||
logError("cancelOrder -> Error = " + err.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
|
||||
openEpisode: openEpisode,
|
||||
updateExitType: updateExitType,
|
||||
closeEpisode: closeEpisode,
|
||||
calculateStatistics: calculateStatistics,
|
||||
cycleBasedStatistics: cycleBasedStatistics,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
@@ -113,37 +113,24 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
|
||||
global.ONE_DAY_IN_MILISECONDS
|
||||
}
|
||||
|
||||
function calculateStatistics() {
|
||||
function cycleBasedStatistics() {
|
||||
|
||||
calculateAssetsStatistics()
|
||||
calculateEpisodeStatistics()
|
||||
|
||||
|
||||
function calculateAssetsStatistics() {
|
||||
|
||||
/* Updating Hits & Fails */
|
||||
if (tradingEngine.current.position.positionBaseAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeBaseAsset.hits.value++
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeBaseAsset.fails.value++
|
||||
}
|
||||
if (tradingEngine.current.position.positionQuotedAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hits.value++
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.fails.value++
|
||||
}
|
||||
|
||||
/* Updating Profit Loss */
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value -
|
||||
sessionParameters.sessionBaseAsset.config.initialBalance
|
||||
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
sessionParameters.sessionQuotedAsset.config.initialBalance
|
||||
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.profitLoss.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value, 10)
|
||||
|
||||
|
||||
/*
|
||||
Updating ROI
|
||||
|
||||
@@ -151,55 +138,57 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
|
||||
*/
|
||||
tradingEngine.current.episode.episodeBaseAsset.ROI.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value /
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * 100
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * 100
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.ROI.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value /
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value * 100
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value * 100
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.ROI.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.ROI.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.ROI.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.ROI.value, 10)
|
||||
|
||||
|
||||
/* Updating Hit Ratio */
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitRatio.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.hits.value /
|
||||
tradingEngine.current.episode.episodeCounters.positions.value
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hits.value /
|
||||
tradingEngine.current.episode.episodeCounters.positions.value
|
||||
|
||||
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)
|
||||
|
||||
if (tradingEngine.current.episode.episodeCounters.positions.value > 0) {
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitRatio.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.hits.value /
|
||||
tradingEngine.current.episode.episodeCounters.positions.value
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hits.value /
|
||||
tradingEngine.current.episode.episodeCounters.positions.value
|
||||
|
||||
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 Annualized Rate Of Return
|
||||
|
||||
https://www.investopedia.com/terms/a/annualized-rate.asp
|
||||
*/
|
||||
tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value =
|
||||
Math.pow(
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value +
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value
|
||||
) / tradingEngine.current.episode.episodeBaseAsset.beginBalance.value
|
||||
,
|
||||
(365 / tradingEngine.current.episode.episodeStatistics.days.value)
|
||||
Math.pow(
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value +
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value
|
||||
) / tradingEngine.current.episode.episodeBaseAsset.beginBalance.value
|
||||
,
|
||||
(365 / tradingEngine.current.episode.episodeStatistics.days.value)
|
||||
) - 1
|
||||
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value =
|
||||
Math.pow(
|
||||
(
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) / tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
,
|
||||
(365 / tradingEngine.current.episode.episodeStatistics.days.value)
|
||||
Math.pow(
|
||||
(
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) / tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
,
|
||||
(365 / tradingEngine.current.episode.episodeStatistics.days.value)
|
||||
) - 1
|
||||
|
||||
|
||||
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) {
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitFail.value = 'Hit'
|
||||
@@ -218,9 +207,9 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
|
||||
tradingEngine.current.episode.episodeStatistics.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value * tradingEngine.current.episode.candle.close.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
|
||||
|
||||
tradingEngine.current.episode.episodeStatistics.profitLoss.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.profitLoss.value, 10)
|
||||
|
||||
|
||||
/*
|
||||
Updating ROI
|
||||
|
||||
@@ -234,32 +223,32 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * tradingEngine.current.episode.beginRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
) * 100
|
||||
|
||||
|
||||
tradingEngine.current.episode.episodeStatistics.ROI.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.ROI.value, 10)
|
||||
|
||||
|
||||
/*
|
||||
Updating Annualized Rate Of Return
|
||||
|
||||
https://www.investopedia.com/terms/a/annualized-rate.asp
|
||||
*/
|
||||
tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value =
|
||||
Math.pow(
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * tradingEngine.current.episode.beginRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value +
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) /
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * tradingEngine.current.episode.beginRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
)
|
||||
,
|
||||
(365 / tradingEngine.current.episode.episodeStatistics.days.value)
|
||||
Math.pow(
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * tradingEngine.current.episode.beginRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value +
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) /
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * tradingEngine.current.episode.beginRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
)
|
||||
,
|
||||
(365 / tradingEngine.current.episode.episodeStatistics.days.value)
|
||||
) - 1
|
||||
|
||||
|
||||
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) {
|
||||
tradingEngine.current.episode.episodeStatistics.hitFail.value = 'Hit'
|
||||
|
||||
@@ -76,6 +76,8 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
tradingSystem.errors.push([executionNode.id, err.message])
|
||||
|
||||
if (typeof err === 'string' || err instanceof String) {
|
||||
logger.write(MODULE_NAME, '[ERROR] runExecution -> err = ' + err)
|
||||
}
|
||||
|
||||
@@ -117,9 +117,9 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
|
||||
switch (tradingEngineOrder.status.value) {
|
||||
case 'Not Open': {
|
||||
{
|
||||
{
|
||||
/* During the First cycle we can not create new orders. That is reserved for the Second cycle. */
|
||||
if (tradingEngine.current.episode.cycle.value === 'First') {continue}
|
||||
if (tradingEngine.current.episode.cycle.value === 'First') { continue }
|
||||
/* When the stage is closing we can not create new orders */
|
||||
if (tradingEngineStage.status.value === 'Closing') { continue }
|
||||
/*
|
||||
@@ -150,14 +150,14 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
await checkExchangeEvents(tradingEngineStage, tradingSystemOrder, tradingEngineOrder)
|
||||
|
||||
/* During the Second cycle we can not cancel orders. That is reserved for the First cycle. */
|
||||
if (tradingEngine.current.episode.cycle.value === 'Second') {continue}
|
||||
if (tradingEngine.current.episode.cycle.value === 'Second') { continue }
|
||||
/*
|
||||
In the previous steps, we might have discovered that the order was cancelled
|
||||
at the exchange, or filled, so the order might still not be Open.
|
||||
If the stage is closing or the order is not Open, we wont be cancelling orders
|
||||
based on defined events.
|
||||
*/
|
||||
if (tradingEngineStage.status.value !== 'Closing' && tradingEngineOrder.status.value === 'Open') {
|
||||
if (tradingEngineStage.status.value !== 'Closing' && tradingEngineOrder.status.value === 'Open') {
|
||||
|
||||
/* Check if we need to Cancel this Order */
|
||||
let situationName = checkOrderEvent(tradingSystemOrder.cancelOrderEvent, tradingSystemOrder, executionAlgorithm, executionNode)
|
||||
@@ -248,7 +248,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
if (tradingSystemOrder.type === 'Limit Buy Order' || tradingSystemOrder.type === 'Limit Sell Order') {
|
||||
if (tradingSystemOrder.orderRate === undefined) { badDefinitionUnhandledException(undefined, 'tradingSystemOrder.orderRate === undefined', tradingSystemOrder) }
|
||||
if (tradingSystemOrder.orderRate.formula === undefined) { badDefinitionUnhandledException(undefined, 'tradingSystemOrder.orderRate.formula === undefined', tradingSystemOrder) }
|
||||
|
||||
|
||||
/* Extract the rate value from the user-defined formula */
|
||||
tradingEngineOrder.rate.value = tradingSystem.formulas.get(tradingSystemOrder.orderRate.formula.id)
|
||||
|
||||
@@ -257,7 +257,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
if (isNaN(tradingEngineOrder.rate.value) === true) { badDefinitionUnhandledException(undefined, 'isNaN(tradingEngineOrder.rate.value) === true', tradingSystemOrder) }
|
||||
if (tradingEngineOrder.rate.value <= 0) { badDefinitionUnhandledException(undefined, 'tradingEngineOrder.rate.value <= 0', tradingSystemOrder) }
|
||||
|
||||
tradingEngineOrder.rate.value = global.PRECISE(tradingEngineOrder.rate.value, 10)
|
||||
tradingEngineOrder.rate.value = global.PRECISE(tradingEngineOrder.rate.value, 10)
|
||||
} else {
|
||||
/*
|
||||
For Market Orders, the rate is irrelevant, since it is not sent to the Exchange.
|
||||
@@ -367,6 +367,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
}
|
||||
}
|
||||
|
||||
let previousQuotedAssetSize = tradingEngineOrder.orderQuotedAsset.size.value
|
||||
let previousBaseAssetSizeFilled = tradingEngineOrder.orderBaseAsset.sizeFilled.value
|
||||
let previousQuotedAssetSizeFilled = tradingEngineOrder.orderQuotedAsset.sizeFilled.value
|
||||
let previousBaseAssetFeesPaid = tradingEngineOrder.orderBaseAsset.feesPaid.value
|
||||
@@ -416,7 +417,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
switch (tradingEngineOrder.type) {
|
||||
case 'Market Order': {
|
||||
/* Actual Rate is simulated based on the Session Paremeters */
|
||||
let slippageAmount = tradingEngineOrder.rate.value * bot.SESSION.parameters.slippage.config.positionRate / 100
|
||||
let slippageAmount = tradingEngineOrder.rate.value * sessionParameters.slippage.config.positionRate / 100
|
||||
switch (tradingSystemOrder.type) {
|
||||
case 'Market Sell Order': {
|
||||
tradingEngineOrder.orderStatistics.actualRate.value = tradingEngineOrder.rate.value - slippageAmount
|
||||
@@ -437,6 +438,24 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
}
|
||||
}
|
||||
tradingEngineOrder.orderStatistics.actualRate.value = global.PRECISE(tradingEngineOrder.orderStatistics.actualRate.value, 10)
|
||||
|
||||
/*
|
||||
Recalculate the Quouted Asset Size based on the newly calculated Actual Rate.
|
||||
*/
|
||||
tradingEngineOrder.orderQuotedAsset.size.value = tradingEngineOrder.orderBaseAsset.size.value * tradingEngineOrder.orderStatistics.actualRate.value
|
||||
tradingEngineOrder.orderQuotedAsset.size.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.size.value, 10)
|
||||
/*
|
||||
Recaulculate the Size Placed Based on the newly calculated Quoted Asset Size.
|
||||
*/
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value =
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value -
|
||||
previousQuotedAssetSize
|
||||
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value =
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value +
|
||||
tradingEngineOrder.orderQuotedAsset.size.value
|
||||
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value = global.PRECISE(tradingEngineStage.stageQuotedAsset.sizePlaced.value, 10)
|
||||
}
|
||||
|
||||
function percentageFilledSimulation() {
|
||||
@@ -463,13 +482,13 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
break
|
||||
}
|
||||
case 'Market Buy Order': {
|
||||
orderWasHit = true
|
||||
orderWasHit = true
|
||||
break
|
||||
}
|
||||
case 'Market Sell Order': {
|
||||
orderWasHit = true
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if (orderWasHit === true) {
|
||||
let calculatedBasedOnTradingSystem = false
|
||||
@@ -515,88 +534,47 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
|
||||
function feesPaidSimulation() {
|
||||
/*
|
||||
The way the fess paid is calculated is as follows: From the order size we apply the % of fee,
|
||||
The way the Fess Paid are 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 !== undefined) {
|
||||
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
|
||||
}
|
||||
applyFeePercentage(tradingEngineOrder, tradingSystemOrder, tradingSystemOrder.simulatedExchangeEvents.simulatedFeesPaid.config.percentage)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
}
|
||||
/*
|
||||
Another way to simulate the Fees Paid is by using the Session Paremeters configuration for Fees.
|
||||
*/
|
||||
switch (tradingEngineOrder.type) {
|
||||
case 'Market Order': {
|
||||
applyFeePercentage(tradingEngineOrder, tradingSystemOrder, sessionParameters.feeStructure.config.taker)
|
||||
break
|
||||
}
|
||||
case 'Limit Order': {
|
||||
applyFeePercentage(tradingEngineOrder, tradingSystemOrder, sessionParameters.feeStructure.config.maker)
|
||||
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 =
|
||||
(tradingEngineOrder.orderBaseAsset.size.value - tradingEngineOrder.orderBaseAsset.feesPaid.value) *
|
||||
tradingEngineOrder.orderBaseAsset.size.value *
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
|
||||
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value =
|
||||
(tradingEngineOrder.orderQuotedAsset.size.value - tradingEngineOrder.orderQuotedAsset.feesPaid.value) *
|
||||
tradingEngineOrder.orderQuotedAsset.size.value *
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
|
||||
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.sizeFilled.value, 10)
|
||||
@@ -667,7 +645,14 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
updateEndsWithCycle(tradingEngineOrder)
|
||||
}
|
||||
|
||||
syncWithExchange(tradingEngineStage, tradingSystemOrder, tradingEngineOrder, order)
|
||||
/*
|
||||
If the order happens to be at least partially filled, there is a syncronization work
|
||||
we need to do, that includes discovering which is the Actual Rate the order is being filled,
|
||||
the Fees Paid and many other thing we need to account for.
|
||||
*/
|
||||
if (order.filled > 0) {
|
||||
syncWithExchange(tradingEngineStage, tradingSystemOrder, tradingEngineOrder, order)
|
||||
}
|
||||
|
||||
/* Forced Cancellation Check */
|
||||
if (tradingEngineStage.status.value === 'Closing' && tradingEngineOrder.status.value !== 'Closed') {
|
||||
@@ -677,44 +662,16 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
|
||||
function syncWithExchange(tradingEngineStage, tradingSystemOrder, tradingEngineOrder, order) {
|
||||
|
||||
let previousQuotedAssetSize = tradingEngineOrder.orderQuotedAsset.size.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
|
||||
|
||||
/* Actual Rate Calculation */
|
||||
tradingEngineOrder.orderStatistics.actualRate.value = order.price
|
||||
tradingEngineOrder.orderStatistics.actualRate.value = global.PRECISE(tradingEngineOrder.orderStatistics.actualRate.value, 10)
|
||||
|
||||
/* Fees Paid Calculation */
|
||||
/*
|
||||
As a response from the exchange we can not always get the fees.
|
||||
For that reason we need to estimate them base of the information that we do have.
|
||||
CCXT provides order.amount which represents the size we set for the order minus the
|
||||
fees taken by the exchange, all denominated in Base Asset.
|
||||
In this way if we substract to the order size this order.amount
|
||||
we can get the fees. All this is denominated in base asset because that is how CCXT works.
|
||||
The fees then can be estimated in Quoted Asset using the Actual Rate.
|
||||
*/
|
||||
tradingEngineOrder.orderBaseAsset.feesPaid.value = tradingEngineOrder.orderBaseAsset.size.value - order.amount
|
||||
tradingEngineOrder.orderBaseAsset.feesPaid.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.feesPaid.value, 10)
|
||||
tradingEngineOrder.orderQuotedAsset.feesPaid.value = tradingEngineOrder.orderBaseAsset.feesPaid.value * tradingEngineOrder.orderStatistics.actualRate.value
|
||||
tradingEngineOrder.orderQuotedAsset.feesPaid.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.feesPaid.value, 10)
|
||||
|
||||
/* Percentage Filled Calculation */
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value = order.filled * 100 / (order.filled + order.remaining)
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value = global.PRECISE(tradingEngineOrder.orderStatistics.percentageFilled.value, 10)
|
||||
|
||||
/* Size Filled Calculation */
|
||||
/*
|
||||
CCXT returns order.filled with an amount denominated in Base Asset. We will
|
||||
take it from there for our Order Base Asset. For our Order Quoted Asset we
|
||||
will use the field order.cost.
|
||||
*/
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value = order.filled
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.sizeFilled.value, 10)
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value = order.cost
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.sizeFilled.value, 10)
|
||||
actualRateCalculation()
|
||||
percentageFilledCalculation()
|
||||
feesPaidCalculation()
|
||||
sizeFilledCalculation()
|
||||
|
||||
doTheAccounting(
|
||||
tradingEngineStage,
|
||||
@@ -725,6 +682,108 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
previousBaseAssetFeesPaid,
|
||||
previousQuotedAssetFeesPaid
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
function actualRateCalculation() {
|
||||
/*
|
||||
Actual Rate Calculation: Let's remember that the exchange may not take the rate
|
||||
we send it with the order (in Limit orders) and for any reason change it a little bit.
|
||||
For example we might have sent a rate with too many decimals and the exchange truncate
|
||||
them. Another thing that might happen is that we send a rate that is matching orders already
|
||||
at the order book. In this case we would get an actual rate not only different than the one
|
||||
we sent, but also, better since the trading engine inside the exchange would match out orders
|
||||
with the first orders best by price.
|
||||
|
||||
In the case of Market Orders we don't even send a rate. For all those reason
|
||||
we get and store the Actual Rate at which the order was filled.
|
||||
*/
|
||||
if (order.average !== undefined) {
|
||||
/*
|
||||
We will use the average whenever is available.
|
||||
*/
|
||||
tradingEngineOrder.orderStatistics.actualRate.value = order.average
|
||||
} else {
|
||||
/*
|
||||
Otherwise we use the order.price.
|
||||
*/
|
||||
tradingEngineOrder.orderStatistics.actualRate.value = order.price
|
||||
}
|
||||
|
||||
tradingEngineOrder.orderStatistics.actualRate.value = global.PRECISE(tradingEngineOrder.orderStatistics.actualRate.value, 10)
|
||||
/*
|
||||
Now we know the Actual Rate at which the order was filled. Since the actual rate
|
||||
might not be the same as the Rate we defined for the order, we need to syncronize
|
||||
the Order Size for Quoted Asset since it was calculated with the Order Size that we
|
||||
now know it is not the once really used at the exchange. We will recalculate the
|
||||
Order Size in Quoted Asset and not in Base Asset, since the Order Size in Base Asset
|
||||
is the one we sent to the exchange, so that is fixed, regardless of how we initially
|
||||
got the Order Size in Base Asset, eigher from direct imput from the user or calculated
|
||||
from the Order Size in Quoted Asset input it by the user. So here we go.
|
||||
*/
|
||||
tradingEngineOrder.orderQuotedAsset.size.value = tradingEngineOrder.orderBaseAsset.size.value * tradingEngineOrder.orderStatistics.actualRate.value
|
||||
tradingEngineOrder.orderQuotedAsset.size.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.size.value, 10)
|
||||
/*
|
||||
Great, this up-to-date order size in Base Asset and the Actual Rate can now be used for example to calculate
|
||||
the orders fees in Quoted Assets, and it is perfectly accurate. The next problem
|
||||
we need to fix is that the sizePlaced for Quoted Asset that we already have calculated
|
||||
was based on the Order Rate, not the Actual Rate, so we need to fix that by anuncounting
|
||||
the previous size and accounting the new one, all this only for Quoted Asset.
|
||||
*/
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value =
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value -
|
||||
previousQuotedAssetSize
|
||||
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value =
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value +
|
||||
tradingEngineOrder.orderQuotedAsset.size.value
|
||||
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value = global.PRECISE(tradingEngineStage.stageQuotedAsset.sizePlaced.value, 10)
|
||||
}
|
||||
|
||||
function percentageFilledCalculation() {
|
||||
/* Percentage Filled Calculation */
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value = order.filled * 100 / (order.filled + order.remaining)
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value = global.PRECISE(tradingEngineOrder.orderStatistics.percentageFilled.value, 10)
|
||||
}
|
||||
|
||||
function feesPaidCalculation() {
|
||||
/*
|
||||
The exchange fees are taken from the Base Asset or the Quoted Asset depending if we
|
||||
are buying or selling. Within the order information received we can not see the fees paid so we need to
|
||||
calculate them by ourselves. To do this it is needed to be used the Session Fees Parameters.
|
||||
*/
|
||||
switch (tradingEngineOrder.type) {
|
||||
case 'Market Order': {
|
||||
applyFeePercentage(tradingEngineOrder, tradingSystemOrder, sessionParameters.feeStructure.config.taker)
|
||||
break
|
||||
}
|
||||
case 'Limit Order': {
|
||||
applyFeePercentage(tradingEngineOrder, tradingSystemOrder, sessionParameters.feeStructure.config.maker)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sizeFilledCalculation() {
|
||||
/*
|
||||
CCXT returns order.filled with an amount denominated in Base Asset. We will
|
||||
take it from there for our Order Base Asset. The amount in order.filled does
|
||||
not account for the fees, which is exactly what we need in this case.
|
||||
*/
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value = order.filled
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderBaseAsset.sizeFilled.value, 10)
|
||||
/*
|
||||
For Quoted Asset, CCXT does not return any field with the size filled, so we
|
||||
need to calculate that by ourselves. Since we know the Size in Quoted Asset thet
|
||||
is already adjusted with the Actual Rate and the Percentage Filled, we will use all
|
||||
this in this formula to get the Size Filled in Quoted Asset.
|
||||
*/
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value =
|
||||
tradingEngineOrder.orderQuotedAsset.size.value * tradingEngineOrder.orderStatistics.percentageFilled.value / 100
|
||||
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value = global.PRECISE(tradingEngineOrder.orderQuotedAsset.sizeFilled.value, 10)
|
||||
}
|
||||
}
|
||||
|
||||
function doTheAccounting(
|
||||
@@ -787,61 +846,72 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
function updateBalances() {
|
||||
/* Balances Update */
|
||||
switch (true) {
|
||||
/*
|
||||
Let's remember that for Buy orders, the fees are paid in Base Asset. So we
|
||||
actually don't receive the whole Size Filled in Base Asset, but the Size
|
||||
Filled minus the Fees Paid. For the case of Quoted Asset, we actually
|
||||
need to susbstract the whole Size Filled from the balance.
|
||||
*/
|
||||
case tradingSystemOrder.type === 'Market Buy Order' || tradingSystemOrder.type === 'Limit Buy Order': {
|
||||
|
||||
/* Balance Base Asset: Undo the previous accounting */
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value -
|
||||
previousBaseAssetSizeFilled
|
||||
|
||||
/* Balance Base Asset: Account the current filling and fees */
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value +
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value
|
||||
|
||||
/* Balance Quoted Asset: Undo the previous accounting */
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value +
|
||||
previousQuotedAssetSizeFilled +
|
||||
previousQuotedAssetFeesPaid
|
||||
|
||||
/* Balance Quoted Asset: Account the current filling and fees */
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value -
|
||||
tradingEngineOrder.orderQuotedAsset.feesPaid.value
|
||||
break
|
||||
}
|
||||
case tradingSystemOrder.type === 'Market Sell Order' || tradingSystemOrder.type === 'Limit Sell Order': {
|
||||
|
||||
/* Balance Base Asset: Undo the previous accounting */
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value +
|
||||
previousBaseAssetSizeFilled +
|
||||
previousBaseAssetFeesPaid
|
||||
|
||||
/* Balance Base Asset: Account the current filling and fees */
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value -
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value +
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value -
|
||||
tradingEngineOrder.orderBaseAsset.feesPaid.value
|
||||
|
||||
/* Balance Quoted Asset: Undo the previous accounting */
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value +
|
||||
previousQuotedAssetSizeFilled
|
||||
|
||||
/* Balance Quoted Asset: Account the current filling and fees */
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value
|
||||
break
|
||||
}
|
||||
/*
|
||||
For Sell orders, the fees are being paid in Quote Asset, so we never
|
||||
acutally receive the whole Filled Size in Quote Asset, but the Filled
|
||||
Size minus the Fees Paid. But we do expend the whole Filled Size in
|
||||
Base Asset.
|
||||
*/
|
||||
case tradingSystemOrder.type === 'Market Sell Order' || tradingSystemOrder.type === 'Limit Sell Order': {
|
||||
|
||||
/* Balance Base Asset: Undo the previous accounting */
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value +
|
||||
previousBaseAssetSizeFilled
|
||||
|
||||
/* Balance Base Asset: Account the current filling and fees */
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value -
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value
|
||||
|
||||
/* Balance Quoted Asset: Undo the previous accounting */
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
previousQuotedAssetSizeFilled +
|
||||
previousQuotedAssetFeesPaid
|
||||
|
||||
/* Balance Quoted Asset: Account the current filling and fees */
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value +
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value -
|
||||
tradingEngineOrder.orderQuotedAsset.feesPaid.value
|
||||
break
|
||||
}
|
||||
}
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.balance.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.balance.value, 10)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function simulateCancelOrder(tradingEngineStage, tradingSystemOrder, tradingEngineOrder, exitType) {
|
||||
@@ -911,7 +981,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
|
||||
syncWithExchange(tradingEngineStage, tradingSystemOrder, tradingEngineOrder, order)
|
||||
|
||||
recalculateStageSize(tradingEngineStage)
|
||||
recalculateStageSize(tradingEngineStage, tradingEngineOrder)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -926,23 +996,51 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
tradingEngineStage.stageBaseAsset.sizePlaced.value =
|
||||
tradingEngineStage.stageBaseAsset.sizePlaced.value -
|
||||
tradingEngineOrder.orderBaseAsset.size.value
|
||||
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value =
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value -
|
||||
tradingEngineOrder.orderQuotedAsset.size.value
|
||||
|
||||
tradingEngineStage.stageBaseAsset.sizePlaced.value =
|
||||
tradingEngineStage.stageBaseAsset.sizePlaced.value +
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value +
|
||||
tradingEngineOrder.orderBaseAsset.feesPaid.value
|
||||
tradingEngineOrder.orderBaseAsset.sizeFilled.value
|
||||
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value =
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value +
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value +
|
||||
tradingEngineOrder.orderQuotedAsset.feesPaid.value
|
||||
tradingEngineOrder.orderQuotedAsset.sizeFilled.value
|
||||
|
||||
tradingEngineStage.stageBaseAsset.sizePlaced.value = global.PRECISE(tradingEngineStage.stageBaseAsset.sizePlaced.value, 10)
|
||||
tradingEngineStage.stageQuotedAsset.sizePlaced.value = global.PRECISE(tradingEngineStage.stageQuotedAsset.sizePlaced.value, 10)
|
||||
}
|
||||
|
||||
function applyFeePercentage(tradingEngineOrder, tradingSystemOrder, feePercentage) {
|
||||
switch (true) {
|
||||
case tradingSystemOrder.type === 'Market Buy Order' || tradingSystemOrder.type === 'Limit Buy Order': {
|
||||
/*
|
||||
In this case the fees are taken from the Base Asset you receive.
|
||||
*/
|
||||
tradingEngineOrder.orderBaseAsset.feesPaid.value =
|
||||
tradingEngineOrder.orderBaseAsset.size.value *
|
||||
feePercentage / 100 *
|
||||
tradingEngineOrder.orderStatistics.percentageFilled.value / 100
|
||||
break
|
||||
}
|
||||
case tradingSystemOrder.type === 'Market Sell Order' || tradingSystemOrder.type === 'Limit Sell Order': {
|
||||
/*
|
||||
In this case the fees are taken from the Quoted Asset you receive.
|
||||
*/
|
||||
tradingEngineOrder.orderQuotedAsset.feesPaid.value =
|
||||
tradingEngineOrder.orderQuotedAsset.size.value *
|
||||
feePercentage / 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 checkOrderEvent(event, order, executionAlgorithm, executionNode) {
|
||||
if (event !== undefined) {
|
||||
for (let k = 0; k < event.situations.length; k++) {
|
||||
|
||||
@@ -6,7 +6,7 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
let thisObject = {
|
||||
mantain: mantain,
|
||||
reset: reset,
|
||||
calculateStatistics: calculateStatistics,
|
||||
cycleBasedStatistics: cycleBasedStatistics,
|
||||
openPosition: openPosition,
|
||||
closingPosition: closingPosition,
|
||||
closePosition: closePosition,
|
||||
@@ -92,6 +92,22 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
Now that the position is closed, it is the right time to move this position from current to last at the Trading Engine data structure.
|
||||
*/
|
||||
tradingEngineModule.cloneValues(tradingEngine.current.position, tradingEngine.last.position)
|
||||
|
||||
cycleBasedStatistics()
|
||||
|
||||
/* Updating Hits & Fails */
|
||||
if (tradingEngine.current.position.positionBaseAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeBaseAsset.hits.value++
|
||||
}
|
||||
if (tradingEngine.current.position.positionBaseAsset.profitLoss.value < 0) {
|
||||
tradingEngine.current.episode.episodeBaseAsset.fails.value++
|
||||
}
|
||||
if (tradingEngine.current.position.positionQuotedAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hits.value++
|
||||
}
|
||||
if (tradingEngine.current.position.positionQuotedAsset.profitLoss.value < 0) {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.fails.value++
|
||||
}
|
||||
}
|
||||
|
||||
function applyStopLossFormula(formulas, formulaId) {
|
||||
@@ -256,47 +272,55 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
}
|
||||
}
|
||||
|
||||
function calculateStatistics(tradingEngineStageNode) {
|
||||
function cycleBasedStatistics() {
|
||||
|
||||
calculateAssetsStatistics()
|
||||
calculatePositionStatistics()
|
||||
|
||||
|
||||
function calculateAssetsStatistics() {
|
||||
/* Profit Loss Calculation */
|
||||
tradingEngine.current.position.positionBaseAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value -
|
||||
tradingEngine.current.position.positionBaseAsset.beginBalance
|
||||
|
||||
|
||||
tradingEngine.current.position.positionQuotedAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
tradingEngine.current.position.positionQuotedAsset.beginBalance
|
||||
|
||||
|
||||
tradingEngine.current.position.positionBaseAsset.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionBaseAsset.profitLoss.value, 10)
|
||||
tradingEngine.current.position.positionQuotedAsset.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionQuotedAsset.profitLoss.value, 10)
|
||||
|
||||
|
||||
/* ROI Calculation */
|
||||
tradingEngine.current.position.positionBaseAsset.ROI.value =
|
||||
tradingEngine.current.position.positionBaseAsset.profitLoss.value * 100 /
|
||||
tradingEngine.current.strategyOpenStage.stageBaseAsset.targetSize.value
|
||||
|
||||
|
||||
tradingEngine.current.position.positionQuotedAsset.ROI.value =
|
||||
tradingEngine.current.position.positionQuotedAsset.profitLoss.value * 100 /
|
||||
tradingEngine.current.strategyOpenStage.stageQuotedAsset.targetSize.value
|
||||
|
||||
|
||||
tradingEngine.current.position.positionBaseAsset.ROI.value = global.PRECISE(tradingEngine.current.position.positionBaseAsset.ROI.value, 10)
|
||||
tradingEngine.current.position.positionQuotedAsset.ROI.value = global.PRECISE(tradingEngine.current.position.positionQuotedAsset.ROI.value, 10)
|
||||
|
||||
|
||||
/* Hit Fail Calculation */
|
||||
if (tradingEngine.current.position.positionBaseAsset.ROI.value > 0) {
|
||||
tradingEngine.current.position.positionBaseAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
}
|
||||
if (tradingEngine.current.position.positionBaseAsset.ROI.value < 0) {
|
||||
tradingEngine.current.position.positionBaseAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
if (tradingEngine.current.position.positionBaseAsset.ROI.value === 0) {
|
||||
tradingEngine.current.position.positionBaseAsset.hitFail.value = 'Even'
|
||||
}
|
||||
if (tradingEngine.current.position.positionQuotedAsset.ROI.value > 0) {
|
||||
tradingEngine.current.position.positionQuotedAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
}
|
||||
if (tradingEngine.current.position.positionQuotedAsset.ROI.value < 0) {
|
||||
tradingEngine.current.position.positionQuotedAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
if (tradingEngine.current.position.positionQuotedAsset.ROI.value === 0) {
|
||||
tradingEngine.current.position.positionQuotedAsset.hitFail.value = 'Even'
|
||||
}
|
||||
}
|
||||
|
||||
function calculatePositionStatistics() {
|
||||
@@ -305,10 +329,10 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value * tradingEngine.current.position.endRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
)
|
||||
)
|
||||
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionStatistics.profitLoss.value, 10)
|
||||
|
||||
|
||||
/* ROI Calculation */
|
||||
tradingEngine.current.position.positionStatistics.ROI.value =
|
||||
(
|
||||
@@ -320,19 +344,23 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
tradingEngine.current.position.positionQuotedAsset.beginBalance
|
||||
)
|
||||
tradingEngine.current.position.positionStatistics.ROI.value = global.PRECISE(tradingEngine.current.position.positionStatistics.ROI.value, 10)
|
||||
|
||||
|
||||
/* Hit Fail Calculation */
|
||||
if (tradingEngine.current.position.positionStatistics.ROI.value > 0) {
|
||||
tradingEngine.current.position.positionStatistics.hitFail.value = 'Hit'
|
||||
} else {
|
||||
}
|
||||
if (tradingEngine.current.position.positionStatistics.ROI.value < 0) {
|
||||
tradingEngine.current.position.positionStatistics.hitFail.value = 'Fail'
|
||||
}
|
||||
|
||||
if (tradingEngine.current.position.positionStatistics.ROI.value === 0) {
|
||||
tradingEngine.current.position.positionStatistics.hitFail.value = 'Even'
|
||||
}
|
||||
|
||||
/* Days Calculation */
|
||||
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.days.value = global.PRECISE(tradingEngine.current.position.positionStatistics.days.value, 10)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
updateChart: updateChart,
|
||||
mantain: mantain,
|
||||
reset: reset,
|
||||
calculateStatistics: calculateStatistics,
|
||||
cycleBasedStatistics: cycleBasedStatistics,
|
||||
runTriggerStage: runTriggerStage,
|
||||
runOpenStage: runOpenStage,
|
||||
runManageStage: runManageStage,
|
||||
@@ -102,9 +102,9 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
resetTradingEngineDataStructure()
|
||||
}
|
||||
|
||||
function calculateStatistics() {
|
||||
tradingEpisodeModule.calculateStatistics()
|
||||
tradingPositionModule.calculateStatistics()
|
||||
function cycleBasedStatistics() {
|
||||
tradingEpisodeModule.cycleBasedStatistics()
|
||||
tradingPositionModule.cycleBasedStatistics()
|
||||
}
|
||||
|
||||
function runTriggerStage() {
|
||||
@@ -359,8 +359,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
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.sizeFilled.value >=
|
||||
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizePlaced.value
|
||||
) {
|
||||
changeStageStatus('Open Stage', 'Closed')
|
||||
@@ -369,8 +368,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
}
|
||||
case 'Quoted Asset': {
|
||||
if (
|
||||
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizeFilled.value +
|
||||
tradingEngine.current.strategyOpenStage.stageQuotedAsset.feesPaid.value >=
|
||||
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizeFilled.value >=
|
||||
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizePlaced.value
|
||||
) {
|
||||
changeStageStatus('Open Stage', 'Closed')
|
||||
@@ -897,10 +895,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
switch (tradingEngineStage.stageDefinedIn.value) {
|
||||
case 'Base Asset': {
|
||||
if (
|
||||
global.PRECISE(
|
||||
tradingEngineStage.stageBaseAsset.sizeFilled.value +
|
||||
tradingEngineStage.stageBaseAsset.feesPaid.value
|
||||
, 10)
|
||||
tradingEngineStage.stageBaseAsset.sizeFilled.value
|
||||
>=
|
||||
tradingEngineStage.stageBaseAsset.targetSize.value
|
||||
) {
|
||||
@@ -912,10 +907,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
}
|
||||
case 'Quoted Asset': {
|
||||
if (
|
||||
global.PRECISE(
|
||||
tradingEngineStage.stageQuotedAsset.sizeFilled.value +
|
||||
tradingEngineStage.stageQuotedAsset.feesPaid.value
|
||||
, 10)
|
||||
tradingEngineStage.stageQuotedAsset.sizeFilled.value
|
||||
>=
|
||||
tradingEngineStage.stageQuotedAsset.targetSize.value
|
||||
) {
|
||||
|
||||
@@ -132,7 +132,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
/* Run the Close Stage */
|
||||
await tradingStagesModule.runCloseStage()
|
||||
|
||||
tradingStagesModule.calculateStatistics()
|
||||
tradingStagesModule.cycleBasedStatistics()
|
||||
|
||||
} catch (err) {
|
||||
/*
|
||||
|
||||
Reference in new issue
Block a user