Files being written fine

This commit is contained in:
Luis Fernando Molina committed 2020-07-19 13:31:19 +02:00
1 parent 139d39ab56
commit 8a65d9e379
4 files changed
+223 -102

No files matched your search

+41 -5
View File
@@ -147,30 +147,66 @@ exports.newTradingEngine = function newTradingEngine(bot, logger) {
}
function updateDistanceToEventsCounters() {
/* Keeping Distance Counters Up-to-date */
/* Keeping Distance Counters Up-to-date while avoinding counting before the first event happens. */
if (
tradingEngine.current.distanceToEvent.triggerOn.value > 0 // with this we avoind counting before the first event happens.
tradingEngine.current.distanceToEvent.triggerOn.value > 0
) {
tradingEngine.current.distanceToEvent.triggerOn.value++
}
if (
tradingEngine.current.distanceToEvent.triggerOff.value > 0 // with this we avoind counting before the first event happens.
tradingEngine.current.distanceToEvent.triggerOff.value > 0
) {
tradingEngine.current.distanceToEvent.triggerOff.value++
}
if (
tradingEngine.current.distanceToEvent.takePosition.value > 0 // with this we avoind counting before the first event happens.
tradingEngine.current.distanceToEvent.takePosition.value > 0
) {
tradingEngine.current.distanceToEvent.takePosition.value++
}
if (
tradingEngine.current.distanceToEvent.closePosition.value > 0 // with this we avoind counting before the first event happens.
tradingEngine.current.distanceToEvent.closePosition.value > 0
) {
tradingEngine.current.distanceToEvent.closePosition.value++
}
if (
tradingEngine.current.distanceToEvent.nextPhase.value > 0
) {
tradingEngine.current.distanceToEvent.nextPhase.value++
}
if (
tradingEngine.current.distanceToEvent.moveToPhase.value > 0
) {
tradingEngine.current.distanceToEvent.moveToPhase.value++
}
if (
tradingEngine.current.distanceToEvent.createOrder.value > 0
) {
tradingEngine.current.distanceToEvent.createOrder.value++
}
if (
tradingEngine.current.distanceToEvent.moveOrder.value > 0
) {
tradingEngine.current.distanceToEvent.moveOrder.value++
}
if (
tradingEngine.current.distanceToEvent.cancelOrder.value > 0
) {
tradingEngine.current.distanceToEvent.cancelOrder.value++
}
if (
tradingEngine.current.distanceToEvent.closeOrder.value > 0
) {
tradingEngine.current.distanceToEvent.closeOrder.value++
}
}
}
+51 -51
View File
@@ -101,57 +101,6 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
}
}
function persistIndividualRecord(record, product, outputDatasetArray) {
if (product.config.saveAsObjects === true) {
/* For saving objects we need to take care of a different set of rules. */
for (let j = 0; j < product.record.properties.length; j++) {
let recordProperty = product.record.properties[j]
if (recordProperty.config.codeName === product.config.propertyNameThatDefinesObject) {
let propertyValue = record[j]
if (bot.processingDailyFiles) {
/*
When dealing with Daily Files, we need to avoid to write an open object at the last 'candle' of the day,
since the object will be duplicated on the next day. How do we know we are positioned at the last candle
of the day? Easy: the end of the candle must be 1 millisecod before the next day. That happens at any
time frame.
*/
let currentDay = new Date(tradingEngine.current.candle.end.value)
let nextDay = new Date(tradingEngine.current.candle.end.value + 1)
if (currentDay.getUTCDate() !== nextDay.getUTCDate()) {
/*
We will save the object only if it is closed, becasuse we are at the last candle of the day.
*/
if (propertyValue === product.config.propertyValueThatClosesObject) {
outputDatasetArray.push(record)
}
} else {
/*
When we are not at the end of the day, we will save the object normally, like in market files.
*/
if (propertyValue !== product.config.propertyValueThatPreventsSavingObject) {
outputDatasetArray.push(record)
}
}
}
else {
/*
For Market Files we will add a record everytime that proeprty value does not match this
*/
if (propertyValue !== product.config.propertyValueThatPreventsSavingObject) {
outputDatasetArray.push(record)
}
}
break
}
}
} else {
/* When we are not dealing with objects, we add every record to the existing file. */
outputDatasetArray.push(record)
}
}
function scanRecordDefinition(product, productRootNode, index) {
let record = []
@@ -232,6 +181,57 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
return record
}
function persistIndividualRecord(record, product, outputDatasetArray) {
if (product.config.saveAsObjects === true) {
/* For saving objects we need to take care of a different set of rules. */
for (let j = 0; j < product.record.properties.length; j++) {
let recordProperty = product.record.properties[j]
if (recordProperty.config.codeName === product.config.propertyNameThatDefinesObject) {
let propertyValue = record[j]
if (bot.processingDailyFiles) {
/*
When dealing with Daily Files, we need to avoid to write an open object at the last 'candle' of the day,
since the object will be duplicated on the next day. How do we know we are positioned at the last candle
of the day? Easy: the end of the candle must be 1 millisecod before the next day. That happens at any
time frame.
*/
let currentDay = new Date(tradingEngine.current.candle.end.value)
let nextDay = new Date(tradingEngine.current.candle.end.value + 1)
if (currentDay.getUTCDate() !== nextDay.getUTCDate()) {
/*
We will save the object only if it is closed, becasuse we are at the last candle of the day.
*/
if (propertyValue === product.config.propertyValueThatClosesObject) {
outputDatasetArray.push(record)
}
} else {
/*
When we are not at the end of the day, we will save the object normally, like in market files.
*/
if (propertyValue !== product.config.propertyValueThatPreventsSavingObject) {
outputDatasetArray.push(record)
}
}
}
else {
/*
For Market Files we will add a record everytime that proeprty value does not match this
*/
if (propertyValue !== product.config.propertyValueThatPreventsSavingObject) {
outputDatasetArray.push(record)
}
}
break
}
}
} else {
/* When we are not dealing with objects, we add every record to the existing file. */
outputDatasetArray.push(record)
}
}
function safeNumericValue(value) {
/*
The purpose of this function is to check that value variable does not have a value that
+1
View File
@@ -141,6 +141,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
tradingSystemModule.reset(chart)
tradingSystemModule.mantainPositions()
tradingSystemModule.mantainStrategies()
tradingSystemModule.mantainOrders()
tradingEngineModule.updateEpisodeCountersAndStatistics()
tradingEngineModule.updateDistanceToEventsCounters()
+130 -46
View File
@@ -8,6 +8,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
reset: reset,
mantainStrategies: mantainStrategies,
mantainPositions: mantainPositions,
mantainOrders: mantainOrders,
triggerStage: triggerStage,
openStage: openStage,
manageStage: manageStage,
@@ -113,6 +114,50 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
tradingPositionModule.updateEnds()
}
function mantainOrders() {
/* Reset All Exchange Orders that are on Closed status, to their initial value */
if (tradingEngine.current.strategy.index.value === tradingEngine.current.strategy.index.config.initialValue) { return }
let stageNode
let executionNode
stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
executionNode = stageNode.openExecution
resetExecution(executionNode)
stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].closeStage
executionNode = stageNode.closeExecution
resetExecution(executionNode)
function resetExecution(executionNode) {
resetExecutionAlgorithms(executionNode)
function resetExecutionAlgorithms(executionNode) {
for (let i = 0; i < executionNode.executionAlgorithms.length; i++) {
let executionAlgorithm = executionNode.executionAlgorithms[i]
resetOrders(executionAlgorithm.marketBuyOrders, executionAlgorithm, executionNode)
resetOrders(executionAlgorithm.marketSellOrders, executionAlgorithm, executionNode)
resetOrders(executionAlgorithm.limitBuyOrders, executionAlgorithm, executionNode)
resetOrders(executionAlgorithm.limitSellOrders, executionAlgorithm, executionNode)
}
}
function resetOrders(orders, executionAlgorithm, executionNode) {
for (let i = 0; i < orders.length; i++) {
let tradingSystemOrder = orders[i]
if (tradingSystemOrder.referenceParent === undefined) { continue }
let tradingEngineOrder = tradingEngineModule.getNodeById(tradingSystemOrder.referenceParent.id)
if (tradingEngineOrder.status === undefined) { continue }
if (tradingEngineOrder.status.value === 'Closed') {
/* We reset the order data structure inside the Trading Engine to its initial value */
tradingEngineOrder.initialize(tradingEngineOrder)
}
}
}
}
}
function evalConditions(startingNode, descendentOfNodeType) {
evalNode(startingNode, 'Conditions', descendentOfNodeType)
}
@@ -319,6 +364,9 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
tradingStrategyModule.openStrategy(j, situation.name, strategy.name)
/* Updating Episode Counters */
tradingEngine.episode.episodeCounters.strategies.value++
/* Initialize this */
tradingEngine.current.distanceToEvent.triggerOn.value = 1
announcementsModule.makeAnnoucements(triggerStage.triggerOn)
@@ -441,6 +489,9 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
/* Opening Status Procedure */
if (tradingEngine.current.strategy.openStageStatus.value === 'Opening') {
/* Reset the Exchange Orders data structure to its initial value */
tradingEngine.exchangeOrders.initialize(tradingEngine.exchangeOrders)
/* This procedure is intended to run only once */
let stageNode = tradingSystem.tradingStrategies[tradingEngine.current.strategy.index.value].openStage
let executionNode = stageNode.openExecution
@@ -919,9 +970,6 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
/* Exiting Everything now. */
exitPositionAndStrategy()
/* Reset Exchange Orders */
tradingEngine.exchangeOrders.initialize(tradingEngine.exchangeOrders)
}
function exitPositionAndStrategy() {
@@ -1094,25 +1142,80 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
if (tradingEngineOrder.orderStatistics.feesPaid === undefined) { continue }
switch (tradingEngineOrder.status.value) {
case 'Not Open': {
{
/* Check if we need to Create this Order */
if (stageIsClosing === true) { continue }
let situationName = checkOrderEvent(tradingSystemOrder.createOrderEvent, tradingSystemOrder, executionAlgorithm, executionNode)
if (situationName !== undefined) {
/* Order Size Calculation */
tradingEngineOrder.size.value = formulas.get(executionAlgorithm.positionSize.formula.id) * tradingSystemOrder.config.positionSizePercentage / 100
if (stageOrdersSize.value + tradingEngineOrder.size.value > stageSizeLimit) {
/* We reduce the size to the remaining size of the position. */
tradingEngineOrder.size.value = stageSizeLimit - stageOrdersSize.value
}
if (tradingEngineOrder.size.value <= 0) { continue }
/* Create Order Procedure */
tradingEngineOrder.identifier.value = global.UNIQUE_ID()
tradingEngineOrder.begin.value = tradingEngine.current.candle.begin.value
tradingEngineOrder.end.value = tradingEngine.current.candle.end.value
tradingEngineOrder.status.value = 'Open'
tradingEngineOrder.orderName.value = tradingSystemOrder.name
tradingEngineOrder.algorithmName.value = executionAlgorithm.name
tradingEngineOrder.situationName.value = situationName
/* Order Rate Calculation */
tradingEngineOrder.rate.value = tradingEngine.current.position.rate.value // By default this is the order rate.
if (tradingSystemOrder.positionRate !== undefined) {
if (tradingSystemOrder.positionRate.formula !== undefined) {
tradingEngineOrder.rate.value = formulas.get(tradingSystemOrder.positionRate.formula.id)
tradingEngineOrder.rate.value = global.PRECISE(tradingEngineOrder.rate.value, 10)
}
}
/* Update State Orders Size */
stageOrdersSize.value = stageOrdersSize.value + tradingEngineOrder.size.value
stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10)
/* Updating Episode Counters */
tradingEngine.episode.episodeCounters.orders.value++
/* Initialize this */
tradingEngine.current.distanceToEvent.createOrder.value = 1
}
}
break
}
case 'Open': {
tradingEngineOrder.end.value = tradingEngine.current.candle.end.value
tradingEngineOrder.orderCounters.periods.value++
tradingEngineOrder.orderStatistics.days.value = tradingEngineOrder.orderCounters.periods.value * sessionParameters.timeFrame.config.value / global.ONE_DAY_IN_MILISECONDS
/* If the stage is closing we wont be moving or cancelling orders based on defined events */
if (stageIsClosing !== true) {
/* Check if we need to Cancel this Order */
let situationName = checkOrderEvent(tradingSystemOrder.cancelOrderEvent, tradingSystemOrder, executionAlgorithm, executionNode)
if (situationName !== undefined) {
/* Since the order was cancelled, we remove the unfilled amount of the order from here */
let unfilledPercentage = 100 - tradingEngineOrder.orderStatistics.percentageFilled.value
let unfilledSize = tradingEngineOrder.size.value * unfilledPercentage / 100
stageOrdersSize.value = stageOrdersSize.value - unfilledSize
stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10)
/* Cancel the Order */
tradingEngineOrder.status.value = 'Closed'
tradingEngineOrder.exitType.value = 'Cancelled by Event'
/* Initialize this */
tradingEngine.current.distanceToEvent.cancelOrder.value = 1
break
}
/* Check if we need to Move this Order */
if (tradingSystemOrder.moveOrderEvents !== undefined) {
for (let j = 0; j < tradingSystemOrder.moveOrderEvents.length; j++) {
let moveOrderEvent = tradingSystemOrder.moveOrderEvents[j]
@@ -1120,9 +1223,13 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
if (situationName !== undefined) {
if (moveOrderEvent.positionRate !== undefined) {
if (moveOrderEvent.positionRate.formula !== undefined) {
/* Move Order to a different Rate */
tradingEngineOrder.rate.value = formulas.get(moveOrderEvent.positionRate.formula.id)
tradingEngineOrder.rate.value = global.PRECISE(tradingEngineOrder.rate.value, 10)
/* Initialize this */
tradingEngine.current.distanceToEvent.moveOrder.value = 1
break
}
}
@@ -1131,58 +1238,18 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
}
}
/* Simulate Events that happens at the Exchange, if needed. */
if (stageIsOpening === false) {
simulateExchangeEvents(tradingSystemOrder, tradingEngineOrder)
}
}
break
case 'Closed': {
// Nothing to do here
}
break
default: {
if (stageIsClosing === true) { continue }
tradingEngineOrder.status.value = 'Not Open'
let situationName = checkOrderEvent(tradingSystemOrder.createOrderEvent, tradingSystemOrder, executionAlgorithm, executionNode)
if (situationName !== undefined) {
/* Order Size Calculation */
tradingEngineOrder.size.value = formulas.get(executionAlgorithm.positionSize.formula.id) * tradingSystemOrder.config.positionSizePercentage / 100
if (stageOrdersSize.value + tradingEngineOrder.size.value > stageSizeLimit) {
/* We reduce the size to the remaining size of the position. */
tradingEngineOrder.size.value = stageSizeLimit - stageOrdersSize.value
}
if (tradingEngineOrder.size.value <= 0) { continue }
/* Create Order Procedure */
tradingEngineOrder.identifier.value = global.UNIQUE_ID()
tradingEngineOrder.begin.value = tradingEngine.current.candle.begin.value
tradingEngineOrder.end.value = tradingEngine.current.candle.end.value
tradingEngineOrder.status.value = 'Open'
tradingEngineOrder.orderName.value = tradingSystemOrder.name
tradingEngineOrder.algorithmName.value = executionAlgorithm.name
tradingEngineOrder.situationName.value = situationName
/* Order Rate Calculation */
tradingEngineOrder.rate.value = tradingEngine.current.position.rate.value // By default this is the order rate.
if (tradingSystemOrder.positionRate !== undefined) {
if (tradingSystemOrder.positionRate.formula !== undefined) {
tradingEngineOrder.rate.value = formulas.get(tradingSystemOrder.positionRate.formula.id)
tradingEngineOrder.rate.value = global.PRECISE(tradingEngineOrder.rate.value, 10)
}
}
stageOrdersSize.value = stageOrdersSize.value + tradingEngineOrder.size.value
stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10)
}
}
}
}
}
function simulateExchangeEvents(tradingSystemOrder, tradingEngineOrder) {
/* Filter by Session Type */
switch (bot.SESSION.type) {
case 'Backtesting Session': {
break
@@ -1198,6 +1265,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
}
}
/* Filter by what is defined at the Strategy */
if (tradingSystemOrder.simulatedExchangeEvents === undefined) { return }
/* Partial Fill Simulation */
@@ -1211,8 +1279,13 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
}
tradingEngineOrder.orderStatistics.percentageFilled.value = tradingEngineOrder.orderStatistics.percentageFilled.value + percentageFilled
if (tradingEngineOrder.orderStatistics.percentageFilled.value === 100) {
/* Close this Order */
tradingEngineOrder.status.value = 'Closed'
tradingEngineOrder.exitType.value = 'Filled'
/* Initialize this */
tradingEngine.current.distanceToEvent.closeOrder.value = 1
}
/* Filled Size Calculation */
@@ -1221,13 +1294,24 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
if (stageIsClosing === true && tradingEngineOrder.status.value !== 'Closed') {
if (tradingEngineOrder.orderStatistics.percentageFilled.value === 0) {
/* Close this Order */
tradingEngineOrder.status.value = 'Closed'
tradingEngineOrder.exitType.value = 'Cancelled by Closing Stage'
/* Initialize this */
tradingEngine.current.distanceToEvent.closeOrder.value = 1
}
if (tradingEngineOrder.orderStatistics.percentageFilled.value > 0 && tradingEngineOrder.orderStatistics.percentageFilled.value < 100) {
/* Close this Order */
tradingEngineOrder.status.value = 'Closed'
tradingEngineOrder.exitType.value = 'Partially Filled'
/* Initialize this */
tradingEngine.current.distanceToEvent.closeOrder.value = 1
}
/* Since the order was cancelled, we remove the unfilled amount of the order from here */
let unfilledPercentage = 100 - tradingEngineOrder.orderStatistics.percentageFilled.value
let unfilledSize = tradingEngineOrder.size.value * unfilledPercentage / 100