Files
Superalgos/TaskServer/LowFrequencyTrading/TradingEpisode.js
T
2020-12-01 13:09:31 +01:00

320 lines
16 KiB
JavaScript

exports.newTradingEpisode = function (processIndex, tradingEngineModule) {
/*
This module packages all functions related to Episodes.
*/
const MODULE_NAME = 'Trading Episode'
let thisObject = {
mantain: mantain,
reset: reset,
openEpisode: openEpisode,
updateExitType: updateExitType,
closeEpisode: closeEpisode,
cycleBasedStatistics: cycleBasedStatistics,
initialize: initialize,
finalize: finalize
}
let tradingEngine
let tradingSystem
let sessionParameters
return thisObject
function initialize() {
tradingSystem = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingSystem
tradingEngine = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingEngine
sessionParameters = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters
}
function finalize() {
tradingEngine = undefined
tradingSystem = undefined
sessionParameters = undefined
}
function mantain() {
updateCounters()
updateStatistics()
updateEnds()
updateDistanceToEventsCounters()
}
function reset() {
resetTradingEngineDataStructure()
}
function openEpisode() {
/*
This function is called each time the simulation starts. That does not mean the Episode
must be opened there, since it might happen that it is looping at the end of the market
or the task / session was restarted. We will only execute if the episode was never opened before.
*/
if (tradingEngine.current.episode.begin.value !== tradingEngine.current.episode.begin.config.initialValue) { return }
/* Starting begin and end */
tradingEngine.current.episode.begin.value = tradingEngine.current.episode.candle.begin.value
tradingEngine.current.episode.end.value = tradingEngine.current.episode.candle.end.value
/* Getting the begin Balance from the session configuration */
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value = sessionParameters.sessionBaseAsset.config.initialBalance
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value = sessionParameters.sessionQuotedAsset.config.initialBalance
/* The current balance is also the begin balance, that is how this starts. */
tradingEngine.current.episode.episodeBaseAsset.balance.value = sessionParameters.sessionBaseAsset.config.initialBalance
tradingEngine.current.episode.episodeQuotedAsset.balance.value = sessionParameters.sessionQuotedAsset.config.initialBalance
/* Recording the opening at the Trading Engine Data Structure */
tradingEngine.current.episode.status.value = 'Open'
tradingEngine.current.episode.serialNumber.value = 1
tradingEngine.current.episode.identifier.value = TS.projects.superalgos.utilities.miscellaneousFunctions.genereteUniqueId()
tradingEngine.current.episode.beginRate.value = tradingEngine.current.episode.candle.close.value
}
function updateExitType(exitType) {
tradingEngine.current.episode.exitType.value = exitType
}
function closeEpisode() {
tradingEngine.current.episode.status.value = 'Closed'
tradingEngine.current.episode.end.value = tradingEngine.current.episode.candle.end.value
tradingEngine.current.episode.endRate.value = tradingEngine.current.episode.candle.close.value
tradingEngine.current.episode.episodeBaseAsset.endBalance.value = tradingEngine.current.episode.episodeBaseAsset.balance.value
tradingEngine.current.episode.episodeQuotedAsset.endBalance.value = tradingEngine.current.episode.episodeQuotedAsset.balance.value
}
function resetEpisode() {
tradingEngineModule.initializeNode(tradingEngine.current.episode)
}
function updateEnds() {
if (tradingEngine.current.episode.status.value === 'Open') {
tradingEngine.current.episode.end.value = tradingEngine.current.episode.end.value + sessionParameters.timeFrame.config.value
tradingEngine.current.episode.endRate.value = tradingEngine.current.episode.candle.close.value
tradingEngine.current.episode.episodeBaseAsset.endBalance.value = tradingEngine.current.episode.episodeBaseAsset.balance.value
tradingEngine.current.episode.episodeQuotedAsset.endBalance.value = tradingEngine.current.episode.episodeQuotedAsset.balance.value
}
}
function resetTradingEngineDataStructure() {
if (tradingEngine.current.episode.status.value === 'Closed') {
resetEpisode()
}
}
function updateCounters() {
if (tradingEngine.current.episode.status.value === 'Open') {
tradingEngine.current.episode.episodeCounters.periods.value++
}
}
function updateStatistics() {
/* Daus Calculation */
tradingEngine.current.episode.episodeStatistics.days.value =
tradingEngine.current.episode.episodeCounters.periods.value *
sessionParameters.timeFrame.config.value /
TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS
}
function cycleBasedStatistics() {
calculateAssetsStatistics()
calculateEpisodeStatistics()
function calculateAssetsStatistics() {
/* 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 = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.current.episode.episodeBaseAsset.profitLoss.value, 10)
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value, 10)
/*
Updating ROI
https://www.investopedia.com/articles/basics/10/guide-to-calculating-roi.asp
*/
tradingEngine.current.episode.episodeBaseAsset.ROI.value =
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value /
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.episodeBaseAsset.ROI.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.current.episode.episodeBaseAsset.ROI.value, 10)
tradingEngine.current.episode.episodeQuotedAsset.ROI.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.current.episode.episodeQuotedAsset.ROI.value, 10)
/* Updating Hit Ratio */
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 = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.current.episode.episodeBaseAsset.hitRatio.value, 10)
tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(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)
) - 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)
) - 1
tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value, 10)
tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(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'
} else {
tradingEngine.current.episode.episodeBaseAsset.hitFail.value = 'Fail'
}
if (tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value > 0) {
tradingEngine.current.episode.episodeQuotedAsset.hitFail.value = 'Hit'
} else {
tradingEngine.current.episode.episodeQuotedAsset.hitFail.value = 'Fail'
}
}
function calculateEpisodeStatistics() {
/* Updating Profit Loss */
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 = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(tradingEngine.current.episode.episodeStatistics.profitLoss.value, 10)
/*
Updating ROI
https://www.investopedia.com/articles/basics/10/guide-to-calculating-roi.asp
*/
tradingEngine.current.episode.episodeStatistics.ROI.value =
(
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value * tradingEngine.current.episode.endRate.value +
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
) / (
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * tradingEngine.current.episode.beginRate.value +
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value
) * 100
tradingEngine.current.episode.episodeStatistics.ROI.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(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)
) - 1
tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value = TS.projects.superalgos.utilities.miscellaneousFunctions.truncateToThisPrecision(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'
} else {
tradingEngine.current.episode.episodeStatistics.hitFail.value = 'Fail'
}
}
}
function updateDistanceToEventsCounters() {
/* Keeping Distance Counters Up-to-date while avoinding counting before the first event happens. */
if (
tradingEngine.current.episode.distanceToEvent.triggerOn.value > 0
) {
tradingEngine.current.episode.distanceToEvent.triggerOn.value++
}
if (
tradingEngine.current.episode.distanceToEvent.triggerOff.value > 0
) {
tradingEngine.current.episode.distanceToEvent.triggerOff.value++
}
if (
tradingEngine.current.episode.distanceToEvent.takePosition.value > 0
) {
tradingEngine.current.episode.distanceToEvent.takePosition.value++
}
if (
tradingEngine.current.episode.distanceToEvent.closePosition.value > 0
) {
tradingEngine.current.episode.distanceToEvent.closePosition.value++
}
if (
tradingEngine.current.episode.distanceToEvent.nextPhase.value > 0
) {
tradingEngine.current.episode.distanceToEvent.nextPhase.value++
}
if (
tradingEngine.current.episode.distanceToEvent.moveToPhase.value > 0
) {
tradingEngine.current.episode.distanceToEvent.moveToPhase.value++
}
if (
tradingEngine.current.episode.distanceToEvent.createOrder.value > 0
) {
tradingEngine.current.episode.distanceToEvent.createOrder.value++
}
if (
tradingEngine.current.episode.distanceToEvent.cancelOrder.value > 0
) {
tradingEngine.current.episode.distanceToEvent.cancelOrder.value++
}
if (
tradingEngine.current.episode.distanceToEvent.closeOrder.value > 0
) {
tradingEngine.current.episode.distanceToEvent.closeOrder.value++
}
}
}