setCurrentCandle

This commit is contained in:
Luis Fernando Molina committed 2020-06-04 16:17:14 +02:00
1 parent b308132ad8
commit 8cf7d3a62b
5 files changed
+223 -178

No files matched your search

+89
View File
@@ -3,6 +3,8 @@ exports.newAnnouncements = function newAnnouncements(bot, logger) {
const MODULE_NAME = 'Announcements'
let thisObject = {
checkAnnouncements: checkAnnouncements,
makeAnnoucements: makeAnnoucements,
initialize: initialize,
finalize: finalize
}
@@ -19,4 +21,91 @@ exports.newAnnouncements = function newAnnouncements(bot, logger) {
tradingEngine = undefined
}
function checkAnnouncements(node, value) {
/*
Value is an optional parameter that represents the value that the announcement is monitoring for change (for numeric values only).
If we do receive this value, we will only make the annoucement if the variance is grater than the user pre-defined value
for this variance.
*/
if (node.announcements !== undefined) {
for (let i = 0; i < node.announcements.length; i++) {
let announcement = node.announcements[i]
let key = node.type + '-' + announcement.name + '-' + announcement.id
let lastPeriodAnnounced = -1
let newAnnouncementRecord = {}
for (let j = 0; j < variable.announcements.length; j++) {
let announcementRecord = variable.announcements[j]
if (announcementRecord.key === key) {
lastPeriodAnnounced = announcementRecord.periods
newAnnouncementRecord = announcementRecord
break
}
}
if (tradingEngine.episode.episodeCounters.periods > lastPeriodAnnounced) {
if (isNaN(value) === false) {
/* The Value Variation is what tells us how much the value already announced must change in order to annouce it again. */
let valueVariation
let config = announcement.config
valueVariation = config.valueVariation
if (newAnnouncementRecord.value !== undefined && valueVariation !== undefined) {
let upperLimit = newAnnouncementRecord.value + newAnnouncementRecord.value * valueVariation / 100
let lowerLimit = newAnnouncementRecord.value - newAnnouncementRecord.value * valueVariation / 100
if (value > lowerLimit && value < upperLimit) {
/* There is not enough variation to announce this again. */
return
}
}
}
/*
We store the announcement temporarily at an Array to differ its execution, becasue we need to evaulate its formula
and at this point in time the potential variables used at the formula are still not set.
*/
announcement.value = value
announcementsToBeMade.push(announcement)
/* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */
if (newAnnouncementRecord.periods !== undefined) {
newAnnouncementRecord.periods = tradingEngine.episode.episodeCounters.periods
newAnnouncementRecord.value = value
} else {
newAnnouncementRecord = {
key: key,
periods: tradingEngine.episode.episodeCounters.periods,
value: value
}
variable.announcements.push(newAnnouncementRecord)
}
}
}
}
}
function makeAnnoucements() {
/* Here we go through all the annoucements that need to be done during this loop, and we just do them. */
for (let i = 0; i < announcementsToBeMade.length; i++) {
announcement = announcementsToBeMade[i]
/* Here we check if there is a formula attached to the annoucement, we evaluate it to get the annoucement text. */
let formulaValue
if (announcement.formula !== undefined) {
try {
let value = announcement.value
formulaValue = eval(announcement.formula.code)
} catch (err) {
announcement.formula.error = err.message
}
}
announcement.formulaValue = formulaValue
if (bot.SESSION.socialBots !== undefined) {
bot.SESSION.socialBots.announce(announcement)
}
}
}
}
+57
View File
@@ -4,6 +4,7 @@ exports.newSnapshots = function newSnapshots(bot, logger) {
let thisObject = {
manageSnapshots: manageSnapshots,
addCodeToSnapshot: addCodeToSnapshot,
initialize: initialize,
finalize: finalize
}
@@ -70,4 +71,60 @@ exports.newSnapshots = function newSnapshots(bot, logger) {
snapshots.headers = closeHeaders.concat(JSON.parse(JSON.stringify(snapshotLoopHeaders)))
}
}
function addCodeToSnapshot(code) {
if (code === undefined) { return }
try {
let instructionsArray = code.split(' ')
for (let i = 0; i < instructionsArray.length; i++) {
let instruction = instructionsArray[i]
instruction = instruction.replace('(', '')
instruction = instruction.replace(')', '')
instruction = instruction.replace(/</g, '')
instruction = instruction.replace(/>/g, '')
instruction = instruction.replace(/<=/g, '')
instruction = instruction.replace(/>=/g, '')
instruction = instruction.replace(/!=/g, '')
instruction = instruction.replace(/!==/g, '')
instruction = instruction.replace(/==/g, '')
instruction = instruction.replace(/===/g, '')
instruction = instruction.replace(/{/g, '')
instruction = instruction.replace(/}/g, '')
if (instruction.indexOf('chart') >= 0) {
let parts = instruction.split('.')
let timeFrame = parts[1]
let product = parts[2]
let property
checkPrevious(3)
function checkPrevious(index) {
property = parts[index]
if (property === 'previous') {
product = product + '.previous'
checkPrevious(index + 1)
}
}
// Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10
if (timeFrame !== 'atAnyvariable.timeFrame') {
timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7)
}
let key = timeFrame + '-' + product + '-' + property
let existingKey = snapshotKeys.get(key)
if (existingKey === undefined) { // means that at the current loop this property of this product was not used before.
snapshotKeys.set(key, key)
snapshotLoopHeaders.push(key)
let value = eval(instruction)
snapshotDataRecord.push(value)
}
}
}
} catch (err) {
logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> code = ' + code)
logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> err = ' + err.stack)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
}
}
}
+53 -1
View File
@@ -3,6 +3,7 @@ exports.newTradingEngine = function newTradingEngine(bot, logger) {
const MODULE_NAME = 'Trading Engine'
let thisObject = {
setCurrentCandle: setCurrentCandle,
updatePositionCounters: updatePositionCounters,
updateDistanceToEventsCounters: updateDistanceToEventsCounters,
getReadyToTakePosition: getReadyToTakePosition,
@@ -32,6 +33,58 @@ exports.newTradingEngine = function newTradingEngine(bot, logger) {
tradingEngine = undefined
}
function setCurrentCandle(candle) {
cloneValues(tradingEngine.current.candle, tradingEngine.previous.candle)
tradingEngine.current.candle.begin.value = candle.begin
tradingEngine.current.candle.end.value = candle.end
tradingEngine.current.candle.open.value = candle.open
tradingEngine.current.candle.close.value = candle.close
tradingEngine.current.candle.min.value = candle.min
tradingEngine.current.candle.max.value = candle.max
}
function cloneValues(originNode, destinationNode) {
if (originNode === undefined) { return }
if (destinationNode === undefined) { return }
/* Here copy the node value */
destinationNode.value = originNode.value
/* Now we go down through all the children of the origin node, assuming the destination node has the same children structure*/
let nodeDefinition = bot.APP_SCHEMA_MAP.get(originNode.type)
if (nodeDefinition === undefined) { return }
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (originNode[property.name] !== undefined && destinationNode[property.name] !== undefined) {
cloneValues(originNode[property.name], destinationNode[property.name])
}
previousPropertyName = property.name
}
break
}
case 'array': {
if (originNode[property.name] !== undefined && destinationNode[property.name] !== undefined) {
let originNodePropertyArray = originNode[property.name]
let destinationNodePropertyArray = destinationNode[property.name]
for (let m = 0; m < originNodePropertyArray.length; m++) {
cloneValues(originNodePropertyArray[m], destinationNodePropertyArray[m])
}
}
break
}
}
}
}
}
function initializeNode(node) {
if (node === undefined) { return }
@@ -64,7 +117,6 @@ exports.newTradingEngine = function newTradingEngine(bot, logger) {
case 'array': {
if (node[property.name] !== undefined) {
let nodePropertyArray = node[property.name]
object[property.name] = []
for (let m = 0; m < nodePropertyArray.length; m++) {
initializeNode(nodePropertyArray[m])
}
+3 -150
View File
@@ -180,6 +180,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
let announcementsToBeMade = []
let candle = candles[currentCandleIndex]
tradingEngineModule.setCurrentCandle(candle)
/* Not processing while out of user-defined time range */
if (candle.end < sessionParameters.timeRange.config.initialDatetime.valueOf()) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Skipping Candle before the sessionParameters.timeRange.config.initialDatetime.') }
@@ -312,8 +314,6 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
}
}
tradingSystemModule.setCandle(candle)
tradingSystemModule.setChart(chart)
tradingSystemModule.evalConditions()
tradingSystemModule.evalFormulas()
@@ -445,156 +445,9 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
tradingEngine.last.candle.end = candle.end
/* After everything at the simulation level was done, we will do the annoucements that are pending. */
makeAnnoucements()
annoucementsModule.makeAnnoucements()
controlLoop()
return
function checkAnnouncements(node, value) {
/*
Value is an optional parameter that represents the value that the announcement is monitoring for change (for numeric values only).
If we do receive this value, we will only make the annoucement if the variance is grater than the user pre-defined value
for this variance.
*/
if (node.announcements !== undefined) {
for (let i = 0; i < node.announcements.length; i++) {
let announcement = node.announcements[i]
let key = node.type + '-' + announcement.name + '-' + announcement.id
let lastPeriodAnnounced = -1
let newAnnouncementRecord = {}
for (let j = 0; j < variable.announcements.length; j++) {
let announcementRecord = variable.announcements[j]
if (announcementRecord.key === key) {
lastPeriodAnnounced = announcementRecord.periods
newAnnouncementRecord = announcementRecord
break
}
}
if (tradingEngine.episode.episodeCounters.periods > lastPeriodAnnounced) {
if (isNaN(value) === false) {
/* The Value Variation is what tells us how much the value already announced must change in order to annouce it again. */
let valueVariation
let config = announcement.config
valueVariation = config.valueVariation
if (newAnnouncementRecord.value !== undefined && valueVariation !== undefined) {
let upperLimit = newAnnouncementRecord.value + newAnnouncementRecord.value * valueVariation / 100
let lowerLimit = newAnnouncementRecord.value - newAnnouncementRecord.value * valueVariation / 100
if (value > lowerLimit && value < upperLimit) {
/* There is not enough variation to announce this again. */
return
}
}
}
/*
We store the announcement temporarily at an Array to differ its execution, becasue we need to evaulate its formula
and at this point in time the potential variables used at the formula are still not set.
*/
announcement.value = value
announcementsToBeMade.push(announcement)
/* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */
if (newAnnouncementRecord.periods !== undefined) {
newAnnouncementRecord.periods = tradingEngine.episode.episodeCounters.periods
newAnnouncementRecord.value = value
} else {
newAnnouncementRecord = {
key: key,
periods: tradingEngine.episode.episodeCounters.periods,
value: value
}
variable.announcements.push(newAnnouncementRecord)
}
}
}
}
}
function makeAnnoucements() {
/* Here we go through all the annoucements that need to be done during this loop, and we just do them. */
for (let i = 0; i < announcementsToBeMade.length; i++) {
announcement = announcementsToBeMade[i]
/* Here we check if there is a formula attached to the annoucement, we evaluate it to get the annoucement text. */
let formulaValue
if (announcement.formula !== undefined) {
try {
let value = announcement.value
formulaValue = eval(announcement.formula.code)
} catch (err) {
announcement.formula.error = err.message
}
}
announcement.formulaValue = formulaValue
if (bot.SESSION.socialBots !== undefined) {
bot.SESSION.socialBots.announce(announcement)
}
}
}
function addCodeToSnapshot(code) {
if (code === undefined) { return }
try {
let instructionsArray = code.split(' ')
for (let i = 0; i < instructionsArray.length; i++) {
let instruction = instructionsArray[i]
instruction = instruction.replace('(', '')
instruction = instruction.replace(')', '')
instruction = instruction.replace(/</g, '')
instruction = instruction.replace(/>/g, '')
instruction = instruction.replace(/<=/g, '')
instruction = instruction.replace(/>=/g, '')
instruction = instruction.replace(/!=/g, '')
instruction = instruction.replace(/!==/g, '')
instruction = instruction.replace(/==/g, '')
instruction = instruction.replace(/===/g, '')
instruction = instruction.replace(/{/g, '')
instruction = instruction.replace(/}/g, '')
if (instruction.indexOf('chart') >= 0) {
let parts = instruction.split('.')
let timeFrame = parts[1]
let product = parts[2]
let property
checkPrevious(3)
function checkPrevious(index) {
property = parts[index]
if (property === 'previous') {
product = product + '.previous'
checkPrevious(index + 1)
}
}
// Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10
if (timeFrame !== 'atAnyvariable.timeFrame') {
timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7)
}
let key = timeFrame + '-' + product + '-' + property
let existingKey = snapshotKeys.get(key)
if (existingKey === undefined) { // means that at the current loop this property of this product was not used before.
snapshotKeys.set(key, key)
snapshotLoopHeaders.push(key)
let value = eval(instruction)
snapshotDataRecord.push(value)
}
}
}
} catch (err) {
logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> code = ' + code)
logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> err = ' + err.stack)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
}
}
}
function controlLoop() {
+21 -27
View File
@@ -4,7 +4,6 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
const FULL_LOG = true
let thisObject = {
setCandle: setCandle,
setChart: setChart,
evalConditions: evalConditions,
evalFormulas: evalFormulas,
@@ -23,7 +22,6 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
}
let chart
let candle
let tradingSystem
let tradingEngine
@@ -45,7 +43,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
function finalize() {
chart = undefined
candle = undefined
tradingSystem = undefined
tradingEngine = undefined
@@ -58,10 +56,6 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
formulasErrors = undefined
}
function setCandle(pCandle) {
candle = pCandle // We need candle to be a local object accessible from conditions and formulas.
}
function setChart(pChart) {
chart = pChart // We need chat to be a local object accessible from conditions and formulas.
}
@@ -260,9 +254,9 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
checkAnnouncements(triggerStage)
tradingEngine.current.strategy.index.value = j
tradingEngine.current.strategy.begin.value = candle.begin
tradingEngine.current.strategy.beginRate.value = candle.min
tradingEngine.current.strategy.endRate.value = candle.min // In case the strategy does not get exited
tradingEngine.current.strategy.begin.value = tradingEngine.current.candle.begin.value
tradingEngine.current.strategy.beginRate.value = tradingEngine.current.candle.min.value
tradingEngine.current.strategy.endRate.value = tradingEngine.current.candle.min.value // In case the strategy does not get exited
tradingEngine.current.strategy.situationName.value = situation.name
tradingEngine.current.strategy.strategyName.value = strategy.name
@@ -307,8 +301,8 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
}
if (passed) {
tradingEngine.current.strategy.end.value = candle.end
tradingEngine.current.strategy.endRate.value = candle.min
tradingEngine.current.strategy.end.value = tradingEngine.current.candle.end.value
tradingEngine.current.strategy.endRate.value = tradingEngine.current.candle.min.value
tradingEngine.current.strategy.status.value = 'Closed'
tradingEngine.current.strategy.stageType.value = 'No Stage'
tradingEngine.current.strategy.index.value = -1
@@ -686,8 +680,8 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
/* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */
if (
(sessionParameters.sessionBaseAsset.name === bot.market.marketBaseAsset && candle.max >= tradingEngine.current.position.stopLoss.value) ||
(sessionParameters.sessionBaseAsset.name !== bot.market.marketBaseAsset && candle.min <= tradingEngine.current.position.stopLoss.value)
(sessionParameters.sessionBaseAsset.name === bot.market.marketBaseAsset && tradingEngine.current.candle.max.value >= tradingEngine.current.position.stopLoss.value) ||
(sessionParameters.sessionBaseAsset.name !== bot.market.marketBaseAsset && tradingEngine.current.candle.min.value <= tradingEngine.current.position.stopLoss.value)
) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Stop Loss was hit.') }
/*
@@ -698,12 +692,12 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
*/
if (sessionParameters.sessionBaseAsset.name === bot.market.marketBaseAsset) {
if (tradingEngine.current.position.stopLoss.value < candle.min) {
tradingEngine.current.position.stopLoss.value = candle.min
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 > candle.max) {
tradingEngine.current.position.stopLoss.value = candle.max
if (tradingEngine.current.position.stopLoss.value > tradingEngine.current.candle.max.value) {
tradingEngine.current.position.stopLoss.value = tradingEngine.current.candle.max.value
}
}
@@ -725,7 +719,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
tradingEngine.current.position.stopLoss.stopLossStage.value = 'No Stage'
tradingEngine.current.position.takeProfit.takeProfitStage.value = 'No Stage'
tradingEngine.current.position.end.value = candle.end
tradingEngine.current.position.end.value = tradingEngine.current.candle.end.value
tradingEngine.current.position.status.value = 1
tradingEngine.current.position.exitType.value = 1
@@ -735,8 +729,8 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
/* Take Profit condition: Here we verify if the Take Profit was hit or not. */
if (
(sessionParameters.sessionBaseAsset.name === bot.market.marketBaseAsset && candle.min <= tradingEngine.current.position.takeProfit.value) ||
(sessionParameters.sessionBaseAsset.name !== bot.market.marketBaseAsset && candle.max >= tradingEngine.current.position.takeProfit.value)
(sessionParameters.sessionBaseAsset.name === bot.market.marketBaseAsset && tradingEngine.current.candle.min.value <= tradingEngine.current.position.takeProfit.value) ||
(sessionParameters.sessionBaseAsset.name !== bot.market.marketBaseAsset && tradingEngine.current.candle.max.value >= tradingEngine.current.position.takeProfit.value)
) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Take Profit was hit.') }
/*
@@ -747,12 +741,12 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
*/
if (sessionParameters.sessionBaseAsset.name === bot.market.marketBaseAsset) {
if (tradingEngine.current.position.takeProfit.value > candle.max) {
tradingEngine.current.position.takeProfit.value = candle.max
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 < candle.min) {
tradingEngine.current.position.takeProfit.value = candle.min
if (tradingEngine.current.position.takeProfit.value < tradingEngine.current.candle.min.value) {
tradingEngine.current.position.takeProfit.value = tradingEngine.current.candle.min.value
}
}
@@ -774,7 +768,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
tradingEngine.current.position.stopLoss.stopLossStage.value = 'No Stage'
tradingEngine.current.position.takeProfit.takeProfitStage.value = 'No Stage'
tradingEngine.current.position.end.value = candle.end
tradingEngine.current.position.end.value = tradingEngine.current.candle.end.value
tradingEngine.current.position.status.value = 1
tradingEngine.current.position.exitType.value = 2
@@ -806,7 +800,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger) {
}
function getPositionRate() {
const DEFAULT_VALUE = candle.close
const DEFAULT_VALUE = tradingEngine.current.candle.close.value
let strategy = tradingSystem.strategies[tradingEngine.current.strategy.index.value]
if (strategy.openStage === undefined) return { DEFAULT_VALUE }