15 files changed
+639
-286
No files matched your search
@@ -8,7 +8,7 @@
|
||||
"url": "https://demo-api-dev.superalgos.org/",
|
||||
"storage": "localStorage",
|
||||
"container": "aamasters",
|
||||
"accessKey": ""
|
||||
"accessKey": "09e890b76767ede3e10f0526b5036600a6b8d3faac540336e12b493fdb2aa9ed46f86094c34652f99fb6322e5f09806412f17725807f85e4dc4169bd22dd59f0b23aba5251f5544478a1aabf5a2dea5260e6eb0c29af3a788208af85025a02f94950437d501b91fd55b9d97b3d6ac3af4e1161321f78b73ca0fda524dc3a5d03"
|
||||
},
|
||||
"bots": [
|
||||
{
|
||||
@@ -728,7 +728,7 @@
|
||||
"url": "https://demo-api-dev.superalgos.org/",
|
||||
"container": "aavikings",
|
||||
"storage": "localStorage",
|
||||
"accessKey": ""
|
||||
"accessKey": "0f38fea438be5adfc5873228f503c55353fb334406128b16a958851b8e47c118a08f0105dd8985d5479758fc4cc3f56c2e2364c2d7c3d0fdffba8d7e9356056a34629e3b926b1ebb940122d973db30b04fc18fab542cbc1afdc032dccf64b0fe308ee6bbc74f82bd350aaebf723428a50d8a699fa2b4b96d58716986ed24069f"
|
||||
},
|
||||
"bots": [
|
||||
{
|
||||
@@ -834,8 +834,8 @@
|
||||
"host": {
|
||||
"url": "https://demo-api-dev.superalgos.org/",
|
||||
"storage": "localStorage",
|
||||
"container": "aaplatform",
|
||||
"accessKey": ""
|
||||
"container": "aamasters",
|
||||
"accessKey": "09e890b76767ede3e10f0526b5036600a6b8d3faac540336e12b493fdb2aa9ed46f86094c34652f99fb6322e5f09806412f17725807f85e4dc4169bd22dd59f0b23aba5251f5544478a1aabf5a2dea5260e6eb0c29af3a788208af85025a02f94950437d501b91fd55b9d97b3d6ac3af4e1161321f78b73ca0fda524dc3a5d03"
|
||||
},
|
||||
"competitions": [
|
||||
{
|
||||
|
||||
@@ -31,6 +31,10 @@ const ecosystemSchema = new Schema({
|
||||
accessKey: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
ownerKey: {
|
||||
type: String,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
bots: [{
|
||||
|
||||
@@ -29,7 +29,7 @@ const resolve = async (parent, { bot }, context) => {
|
||||
if (auxProduct.codeName === bot.productCodeName) {
|
||||
newBotClone = {
|
||||
displayName: auxBot.displayName,
|
||||
codeName: auxBot.codeName + '-' + bot.cloneId,
|
||||
codeName: auxBot.codeName,
|
||||
type: auxBot.type,
|
||||
profilePicture: auxBot.profilePicture,
|
||||
cloneId: bot.cloneId,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { TeamInputType } from '../types/input'
|
||||
import { copyBot } from '../../storage/CopyBot'
|
||||
import { copySimulator } from '../../storage/CopySimulator'
|
||||
import { createContainer, writeFileContent } from '../../storage/providers/MinioStorage'
|
||||
import crypto from 'crypto'
|
||||
|
||||
export const args = { team: { type: TeamInputType } }
|
||||
|
||||
@@ -51,7 +52,8 @@ const resolve = async (parent, { team }, context) => {
|
||||
url: process.env.NODE_ENDPOINT,
|
||||
storage: 'localStorage',
|
||||
container: team.codeName,
|
||||
accessKey: '',
|
||||
accessKey: crypto.randomBytes(128).toString('hex'),
|
||||
ownerKey: crypto.randomBytes(128).toString('hex')
|
||||
}
|
||||
team.host = nodeEndpoint
|
||||
}
|
||||
|
||||
@@ -2,14 +2,26 @@ import logger from '../../utils/logger'
|
||||
import { FileInputType } from '../types/input'
|
||||
import { GraphQLString } from 'graphql'
|
||||
import { writeFileContent } from '../../storage/providers/MinioStorage'
|
||||
import { AuthenticationError, WrongArgumentsError } from '../../errors'
|
||||
import getDevTeamHost from '../../utils/getDevTeamHost'
|
||||
|
||||
export const args = { file: { type: FileInputType } }
|
||||
|
||||
const resolve = async (parent, { file }, context) => {
|
||||
logger.debug('createFile -> Entering Function: ' + file.container + '/' + file.filePath)
|
||||
try {
|
||||
//TODO Add permissions
|
||||
if (file.accessKey === undefined || file.accessKey === null) {
|
||||
throw new WrongArgumentsError()
|
||||
}
|
||||
|
||||
let host = await getDevTeamHost(file.container, undefined, file.accessKey)
|
||||
|
||||
if (host === undefined || host === null) {
|
||||
throw new AuthenticationError()
|
||||
}
|
||||
let date = new Date()
|
||||
await writeFileContent(file.container, file.filePath, file.fileContent)
|
||||
let dateAfter = new Date()
|
||||
logger.info('createFile: ' + file.container + '/...' + file.filePath.substring(file.filePath.length -110 , file.filePath.length) + ', ' + (dateAfter - date))
|
||||
return 'File created.'
|
||||
} catch (err) {
|
||||
logger.error('createFile -> Error: %s', err.message)
|
||||
|
||||
@@ -23,7 +23,7 @@ const resolve = async (parent, { bot }, context) => {
|
||||
if (auxTeam.codeName === bot.devTeam) {
|
||||
for (let j = 0; j < auxTeam.bots.length; j++) {
|
||||
const auxBot = auxTeam.bots[j]
|
||||
if (auxBot.codeName + '-' + bot.cloneId === bot.codeName) {
|
||||
if (auxBot.codeName === bot.codeName && auxBot.cloneId === bot.cloneId) {
|
||||
for (let k = 0; k < auxBot.products.length; k++) {
|
||||
const auxProduct = auxBot.products[k]
|
||||
if (auxProduct.codeName === bot.productCodeName) {
|
||||
|
||||
@@ -2,28 +2,33 @@ import logger from '../../utils/logger'
|
||||
import { FileInputType } from '../types/input'
|
||||
import { GraphQLString } from 'graphql'
|
||||
import { getFileContent } from '../../storage/providers/MinioStorage'
|
||||
import { getFileContentRemote } from '../../storage/providers/AzureStorage'
|
||||
import { AuthenticationError, WrongArgumentsError } from '../../errors'
|
||||
import getDevTeamHost from '../../utils/getDevTeamHost'
|
||||
|
||||
export const args = { file: { type: FileInputType } }
|
||||
|
||||
const resolve = async (parent, { file }, context) => {
|
||||
logger.debug('getFileContent -> Entering Function: ' + file.container + '/' + file.filePath)
|
||||
|
||||
try {
|
||||
|
||||
let fileContent
|
||||
if (file.storage === 'localStorage') {
|
||||
//TODO Add permissions
|
||||
fileContent = await getFileContent(file.container, file.filePath)
|
||||
} else {
|
||||
fileContent = await getFileContentRemote(file.container, file.filePath, file.storage, file.accessKey)
|
||||
if (file.accessKey === undefined || file.accessKey === null) {
|
||||
throw new WrongArgumentsError()
|
||||
}
|
||||
|
||||
let host = await getDevTeamHost(file.container, file.accessKey)
|
||||
|
||||
if (host === undefined || host === null) {
|
||||
logger.error('Error getting file:' + JSON.stringify(file))
|
||||
throw new AuthenticationError()
|
||||
}
|
||||
|
||||
let date = new Date()
|
||||
let fileContent = await getFileContent(file.container, file.filePath)
|
||||
let dateAfter = new Date()
|
||||
logger.info('getFileContent: ' + file.container + '/...' + file.filePath.substring(file.filePath.length -110 , file.filePath.length) + ', ' + (dateAfter - date))
|
||||
return fileContent
|
||||
|
||||
} catch (err) {
|
||||
if (err.message === 'The specified key does not exist.')
|
||||
logger.warn('getFileContent -> Error: %s', err.message)
|
||||
logger.debug('getFileContent -> Error: %s', err.message)
|
||||
else {
|
||||
logger.error('getFileContent -> Error: %s', err.message)
|
||||
throw err
|
||||
|
||||
@@ -9,7 +9,8 @@ const HostType = new GraphQLObjectType({
|
||||
url: { type: GraphQLString },
|
||||
storage: { type: GraphQLString },
|
||||
container: { type: GraphQLString },
|
||||
accessKey: { type: GraphQLString }
|
||||
accessKey: { type: GraphQLString },
|
||||
ownerKey: { type: GraphQLString }
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> Entering function."); }
|
||||
|
||||
let executionArray = [];
|
||||
let recordsArray = [];
|
||||
let conditionsArray = [];
|
||||
let strategiesArray = [];
|
||||
@@ -183,8 +184,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
/* Simulation Records */
|
||||
|
||||
let positionRate = 0;
|
||||
let positionSize = 0;
|
||||
let tradePositionRate = 0;
|
||||
let tradePositionSize = 0;
|
||||
let positionInstant;
|
||||
|
||||
let previousBalanceAssetA = 0;
|
||||
@@ -341,36 +342,56 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
|
||||
/* Update all the data objects available for the simulation. */
|
||||
|
||||
let candle = candles[i];
|
||||
let percentageBandwidth = percentageBandwidthMap.get(candle.begin);
|
||||
let bollingerBand = bollingerBandsMap.get(candle.begin);
|
||||
let bollingerChannel = getElement(bollingerChannelsArray, candle.begin, candle.end);
|
||||
let bollingerSubChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end);
|
||||
|
||||
//let LRC = LRCMap.get(candle.begin);
|
||||
|
||||
//if (LRC === undefined) { continue; }
|
||||
if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles.
|
||||
/* If any of the needed indicators is missing, then that period is not calculated */
|
||||
|
||||
if (candle.begin < initialDate.valueOf()) { continue; }
|
||||
if (bollingerBand === undefined) { continue; }
|
||||
if (percentageBandwidth === undefined) { continue; } // percentageBandwidth might start after the first few candles.
|
||||
if (bollingerChannel === undefined) { continue; }
|
||||
if (bollingerSubChannel === undefined) { continue; }
|
||||
|
||||
//if (LRC === undefined) { continue; }
|
||||
|
||||
periods++;
|
||||
days = periods * timePeriod / ONE_DAY_IN_MILISECONDS;
|
||||
|
||||
if (currentDay !== undefined) {
|
||||
if (currentDay !== undefined) { // This means that we are processing Daily Files
|
||||
if (candle.end < currentDay.valueOf()) {
|
||||
yesterday.Periods++;
|
||||
}
|
||||
}
|
||||
|
||||
let channel = getElement(bollingerChannelsArray, candle.begin, candle.end);
|
||||
let subChannel = getElement(bollingerSubChannelsArray, candle.begin, candle.end);
|
||||
/* We skip the candle at the head of the market because i has not closed yet. */
|
||||
let candlesPerDay = ONE_DAY_IN_MILISECONDS / timePeriod
|
||||
if (i === candles.length - 1) {
|
||||
if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2) ) {
|
||||
/*We are at the head of the market, thus we skip the last candle because it has not close yet. */
|
||||
continue;
|
||||
/* Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators.
|
||||
if we skip these two periods, then there will be a hole in the file since the last period will be missing. */
|
||||
}
|
||||
}
|
||||
} else { // We are processing Market Files
|
||||
if (i === candles.length - 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let lastObjects = {
|
||||
candle: clone(candle),
|
||||
//LRC: clone(LRC),
|
||||
bollingerBand: clone(bollingerBand),
|
||||
percentageBandwidth: clone(percentageBandwidth),
|
||||
channel: clone(channel),
|
||||
subChannel: clone(subChannel)
|
||||
bollingerChannel: clone(bollingerChannel),
|
||||
bollingerSubChannel: clone(bollingerSubChannel)
|
||||
}
|
||||
|
||||
function clone(obj) {
|
||||
@@ -386,8 +407,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
//lastObjects.LRC.previous = undefined;
|
||||
lastObjects.bollingerBand.previous = undefined;
|
||||
lastObjects.percentageBandwidth.previous = undefined;
|
||||
lastObjects.channel.previous = undefined;
|
||||
lastObjects.subChannel.previous = undefined;
|
||||
lastObjects.bollingerChannel.previous = undefined;
|
||||
lastObjects.bollingerSubChannel.previous = undefined;
|
||||
|
||||
lastObjectsArray.push(lastObjects);
|
||||
|
||||
@@ -415,6 +436,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
let strategy = tradingSystem.strategies[j];
|
||||
|
||||
let positionSize = 0
|
||||
let positionRate = 0
|
||||
|
||||
/* Continue with the rest of the formulas and conditions */
|
||||
|
||||
let triggerStage = strategy.triggerStage
|
||||
|
||||
if (triggerStage !== undefined) {
|
||||
@@ -478,10 +504,67 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
if (openStage !== undefined) {
|
||||
|
||||
/* Default Values*/
|
||||
if (baseAsset === 'BTC') {
|
||||
positionSize = balanceAssetA;
|
||||
positionRate = candle.close;
|
||||
} else {
|
||||
positionSize = balanceAssetB;
|
||||
positionRate = candle.close;
|
||||
}
|
||||
|
||||
let initialDefinition = openStage.initialDefinition
|
||||
|
||||
if (initialDefinition !== undefined) {
|
||||
|
||||
if (tradePositionSize !== 0) {
|
||||
positionSize = tradePositionSize
|
||||
} else {
|
||||
if (initialDefinition.positionSize !== undefined) {
|
||||
if (initialDefinition.positionSize.formula !== undefined) {
|
||||
try {
|
||||
positionSize = eval(initialDefinition.positionSize.formula.code);
|
||||
} catch (err) {
|
||||
initialDefinition.positionSize.formula.error = err.message
|
||||
}
|
||||
if (isNaN(positionSize)) {
|
||||
if (baseAsset === 'BTC') {
|
||||
positionSize = balanceAssetA;
|
||||
} else {
|
||||
positionSize = balanceAssetB;
|
||||
}
|
||||
} else {
|
||||
if (baseAsset === 'BTC') {
|
||||
if (positionSize > balanceAssetA) { positionSize = balanceAssetA }
|
||||
} else {
|
||||
if (positionSize > balanceAssetB) { positionSize = balanceAssetB }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tradePositionRate !== 0) {
|
||||
positionRate = tradePositionRate
|
||||
} else {
|
||||
if (initialDefinition.positionRate !== undefined) {
|
||||
if (initialDefinition.positionRate.formula !== undefined) {
|
||||
try {
|
||||
positionRate = eval(initialDefinition.positionRate.formula.code);
|
||||
} catch (err) {
|
||||
initialDefinition.positionRate.formula.error = err.message
|
||||
}
|
||||
if (isNaN(positionRate)) {
|
||||
if (baseAsset === 'BTC') {
|
||||
positionRate = candle.close;
|
||||
} else {
|
||||
positionRate = candle.close;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (initialDefinition.stopLoss !== undefined) {
|
||||
|
||||
for (let p = 0; p < initialDefinition.stopLoss.phases.length; p++) {
|
||||
@@ -500,7 +583,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
formulaValue = MAX_STOP_LOSS_VALUE
|
||||
}
|
||||
} catch (err) {
|
||||
formulaError = err.message
|
||||
if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) {
|
||||
/*
|
||||
We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined.
|
||||
*/
|
||||
} else {
|
||||
formulaError = err.message
|
||||
}
|
||||
}
|
||||
if (isNaN(formulaValue)) { formulaValue = 0; }
|
||||
if (formulaValue < MIN_STOP_LOSS_VALUE) {
|
||||
@@ -553,7 +642,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
formulaValue = MAX_TAKE_PROFIT_VALUE
|
||||
}
|
||||
} catch (err) {
|
||||
formulaError = err.message
|
||||
if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) {
|
||||
/*
|
||||
We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined.
|
||||
*/
|
||||
} else {
|
||||
formulaError = err.message
|
||||
}
|
||||
}
|
||||
if (isNaN(formulaValue)) { formulaValue = 0; }
|
||||
if (formulaValue < MIN_TAKE_PROFIT_VALUE) {
|
||||
@@ -588,6 +683,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strategy.positionSize = positionSize
|
||||
strategy.positionRate = positionRate
|
||||
}
|
||||
|
||||
let manageStage = strategy.manageStage
|
||||
@@ -612,7 +710,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
formulaValue = MAX_STOP_LOSS_VALUE
|
||||
}
|
||||
} catch (err) {
|
||||
formulaError = err.message
|
||||
if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) {
|
||||
/*
|
||||
We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined.
|
||||
*/
|
||||
} else {
|
||||
formulaError = err.message
|
||||
}
|
||||
}
|
||||
if (isNaN(formulaValue)) { formulaValue = 0; }
|
||||
if (formulaValue < MIN_STOP_LOSS_VALUE) {
|
||||
@@ -665,7 +769,13 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
formulaValue = MAX_TAKE_PROFIT_VALUE
|
||||
}
|
||||
} catch (err) {
|
||||
formulaError = err.message
|
||||
if (phase.formula.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) {
|
||||
/*
|
||||
We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined.
|
||||
*/
|
||||
} else {
|
||||
formulaError = err.message
|
||||
}
|
||||
}
|
||||
if (isNaN(formulaValue)) { formulaValue = 0; }
|
||||
if (formulaValue < MIN_TAKE_PROFIT_VALUE) {
|
||||
@@ -700,39 +810,45 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function newCondition(key, node) {
|
||||
function newCondition(key, node) {
|
||||
|
||||
let condition;
|
||||
let error = ''
|
||||
let value
|
||||
let condition;
|
||||
let error = ''
|
||||
let value
|
||||
|
||||
try {
|
||||
value = eval(node.code);
|
||||
} catch (err) {
|
||||
/*
|
||||
One possible error is that the conditions references a .previous that is undefined. For this
|
||||
reason and others, we will simply set the value to false.
|
||||
*/
|
||||
value = false
|
||||
node.error = err.message
|
||||
}
|
||||
try {
|
||||
value = eval(node.code);
|
||||
} catch (err) {
|
||||
/*
|
||||
One possible error is that the conditions references a .previous that is undefined. For this
|
||||
reason and others, we will simply set the value to false.
|
||||
*/
|
||||
value = false
|
||||
|
||||
condition = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
if (node.code.indexOf('previous') > 0 && err.message.indexOf('of undefined') > 0) {
|
||||
/*
|
||||
We are not going to set an error for the casess we are using previous and the error is that the indicator is undefined.
|
||||
*/
|
||||
} else {
|
||||
node.error = err.message
|
||||
}
|
||||
}
|
||||
|
||||
conditions.set(condition.key, condition);
|
||||
condition = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
|
||||
if (condition.value) {
|
||||
conditionsArrayValues.push(1);
|
||||
} else {
|
||||
conditionsArrayValues.push(0);
|
||||
conditions.set(condition.key, condition);
|
||||
|
||||
if (condition.value) {
|
||||
conditionsArrayValues.push(1);
|
||||
} else {
|
||||
conditionsArrayValues.push(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Trigger On Conditions */
|
||||
@@ -809,11 +925,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let stopRunningDate = new Date(candle.begin)
|
||||
if (balance < minimumBalance) {
|
||||
tradingSystem.error = "Balance below the minimum."
|
||||
tradingSystem.error = "Min Balance @ " + stopRunningDate.toUTCString()
|
||||
}
|
||||
if (balance > maximumBalance) {
|
||||
tradingSystem.error = "Balance above the maximum."
|
||||
tradingSystem.error = "Max Balance @ " + stopRunningDate.toUTCString()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -893,7 +1010,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
if (passed) {
|
||||
|
||||
type = '"Sell"';
|
||||
type = '"Take Position"';
|
||||
|
||||
strategyStage = 'Open Stage';
|
||||
stopLossStage = 'Open Stage';
|
||||
@@ -1153,7 +1270,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
}
|
||||
|
||||
marketRate = stopLoss;
|
||||
type = '"Buy@StopLoss"';
|
||||
type = '"Close@StopLoss"';
|
||||
strategyStage = 'Close Stage';
|
||||
stopLossStage = 'No Stage';
|
||||
takeProfitStage = 'No Stage';
|
||||
@@ -1189,7 +1306,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
}
|
||||
|
||||
marketRate = takeProfit;
|
||||
type = '"Buy@TakeProfit"';
|
||||
type = '"Close@TakeProfit"';
|
||||
strategyStage = 'Close Stage';
|
||||
stopLossStage = 'No Stage';
|
||||
takeProfitStage = 'No Stage';
|
||||
@@ -1211,44 +1328,24 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
) {
|
||||
takePositionNow = false
|
||||
|
||||
/* positionSize default is the whole balance if no size was defined by the user */
|
||||
/* tradePositionSize default is the whole balance if no size was defined by the user */
|
||||
if (baseAsset === 'BTC') {
|
||||
positionSize = balanceAssetA;
|
||||
tradePositionSize = balanceAssetA;
|
||||
} else {
|
||||
positionSize = balanceAssetB;
|
||||
tradePositionSize = balanceAssetB;
|
||||
}
|
||||
tradePositionRate = candle.close
|
||||
|
||||
/* Check if the user defined a position size */
|
||||
/* Check if the user defined a position size or rate */
|
||||
let strategy = tradingSystem.strategies[currentStrategyIndex];
|
||||
let triggerStage = strategy.triggerStage
|
||||
|
||||
if (triggerStage !== undefined) {
|
||||
if (triggerStage.positionSize !== undefined) {
|
||||
if (triggerStage.positionSize.formula !== undefined) {
|
||||
try {
|
||||
positionSize = eval(triggerStage.positionSize.formula.code);
|
||||
} catch (err) {
|
||||
triggerStage.positionSize.formula.error = err.message
|
||||
}
|
||||
if (isNaN(positionSize)) {
|
||||
if (baseAsset === 'BTC') {
|
||||
positionSize = balanceAssetA;
|
||||
} else {
|
||||
positionSize = balanceAssetB;
|
||||
}
|
||||
} else {
|
||||
if (baseAsset === 'BTC') {
|
||||
if (positionSize > balanceAssetA) { positionSize = balanceAssetA}
|
||||
} else {
|
||||
if (positionSize > balanceAssetB) { positionSize = balanceAssetB}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tradePositionSize = strategy.positionSize;
|
||||
tradePositionRate = strategy.positionRate;
|
||||
|
||||
calculateTakeProfit();
|
||||
calculateStopLoss();
|
||||
|
||||
marketRate = candle.close;
|
||||
positionRate = candle.close;
|
||||
|
||||
previousBalanceAssetA = balanceAssetA;
|
||||
previousBalanceAssetB = balanceAssetB;
|
||||
@@ -1257,11 +1354,11 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
lastTradeROI = 0;
|
||||
|
||||
if (baseAsset === 'BTC') {
|
||||
balanceAssetB = balanceAssetB + positionSize * positionRate;
|
||||
balanceAssetA = balanceAssetA - positionSize;
|
||||
balanceAssetB = balanceAssetB + tradePositionSize * tradePositionRate;
|
||||
balanceAssetA = balanceAssetA - tradePositionSize;
|
||||
} else {
|
||||
balanceAssetA = balanceAssetA + positionSize / positionRate;
|
||||
balanceAssetB = balanceAssetB - positionSize;
|
||||
balanceAssetA = balanceAssetA + tradePositionSize / tradePositionRate;
|
||||
balanceAssetB = balanceAssetB - tradePositionSize;
|
||||
}
|
||||
|
||||
positionInstant = candle.end;
|
||||
@@ -1293,12 +1390,12 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
if (baseAsset === 'BTC') {
|
||||
lastTradeProfitLoss = balanceAssetA - previousBalanceAssetA;
|
||||
lastTradeROI = lastTradeProfitLoss * 100 / positionSize;
|
||||
lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize;
|
||||
if (isNaN(lastTradeROI)) { lastTradeROI = 0; }
|
||||
profit = balanceAssetA - initialBalanceA;
|
||||
} else {
|
||||
lastTradeProfitLoss = balanceAssetB - previousBalanceAssetB;
|
||||
lastTradeROI = lastTradeProfitLoss * 100 / positionSize;
|
||||
lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize;
|
||||
if (isNaN(lastTradeROI)) { lastTradeROI = 0; }
|
||||
profit = balanceAssetB - initialBalanceB;
|
||||
}
|
||||
@@ -1356,8 +1453,8 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
currentStrategyIndex = -1;
|
||||
stopLoss = 0;
|
||||
positionRate = 0;
|
||||
positionSize = 0;
|
||||
tradePositionRate = 0;
|
||||
tradePositionSize = 0;
|
||||
positionInstant = undefined;
|
||||
takeProfit = 0;
|
||||
strategyStage = 'No Stage';
|
||||
@@ -1380,21 +1477,33 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
let messageType;
|
||||
let message;
|
||||
let simulationRecord;
|
||||
let orderRecord;
|
||||
let executionRecord;
|
||||
let executionMessage;
|
||||
|
||||
messageId++;
|
||||
|
||||
if (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage') {
|
||||
if (strategyStage === 'Open Stage' || strategyStage === 'Manage Stage' || type === '"Close@TakeProfit"' || type === '"Close@StopLoss"') {
|
||||
|
||||
if (strategyStage === 'Open Stage') {
|
||||
if (type === '"Take Position"') {
|
||||
messageType = MESSAGE_TYPE.Order;
|
||||
orderId++;
|
||||
}
|
||||
if (strategyStage === 'Manage Stage') {
|
||||
messageType = MESSAGE_TYPE.OrderUpdate;
|
||||
} else {
|
||||
if (type === '"Close@TakeProfit"' || type === '"Close@StopLoss"') {
|
||||
messageType = MESSAGE_TYPE.OrderClose;
|
||||
} else {
|
||||
messageType = MESSAGE_TYPE.OrderUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
orderRecord = createMessage(
|
||||
let exitOutcome = ""
|
||||
if (messageType === MESSAGE_TYPE.OrderClose && type === '"Close@TakeProfit"') {
|
||||
exitOutcome = "TP"
|
||||
}
|
||||
if (messageType === MESSAGE_TYPE.OrderClose && type === '"Close@StopLoss"') {
|
||||
exitOutcome = "SL"
|
||||
}
|
||||
|
||||
executionMessage = createMessage(
|
||||
messageId,
|
||||
MESSAGE_ENTITY.SimulationEngine,
|
||||
MESSAGE_ENTITY.SimulationExecutor,
|
||||
@@ -1408,19 +1517,19 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
"BTC_USDT",
|
||||
0,
|
||||
ORDER_TYPE.Limit,
|
||||
marketRate,
|
||||
tradePositionRate,
|
||||
stopLoss,
|
||||
takeProfit,
|
||||
ORDER_DIRECTION.Sell,
|
||||
-1,
|
||||
ORDER_STATUS.Signaled,
|
||||
0,
|
||||
"")
|
||||
exitOutcome)
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
orderRecord = createMessage(
|
||||
executionMessage = createMessage(
|
||||
messageId,
|
||||
MESSAGE_ENTITY.SimulationEngine,
|
||||
MESSAGE_ENTITY.SimulationExecutor,
|
||||
@@ -1444,6 +1553,14 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
"")
|
||||
}
|
||||
|
||||
executionRecord = {
|
||||
begin: candle.begin,
|
||||
end: candle.end,
|
||||
executionRecord: executionMessage
|
||||
}
|
||||
|
||||
executionArray.push(executionRecord)
|
||||
|
||||
let strategyStageNumber
|
||||
switch (strategyStage) {
|
||||
case 'No Stage': {
|
||||
@@ -1497,15 +1614,15 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
periods: periods,
|
||||
days: days,
|
||||
anualizedRateOfReturn: anualizedRateOfReturn,
|
||||
positionRate: positionRate,
|
||||
positionRate: tradePositionRate,
|
||||
lastTradeROI: lastTradeROI,
|
||||
strategy: currentStrategyIndex,
|
||||
strategyStageNumber: strategyStageNumber,
|
||||
takeProfit: takeProfit,
|
||||
stopLossPhase: stopLossPhase,
|
||||
takeProfitPhase: takeProfitPhase,
|
||||
orderRecord: orderRecord,
|
||||
positionSize: positionSize,
|
||||
executionRecord: executionMessage,
|
||||
positionSize: tradePositionSize,
|
||||
initialBalanceA: initialBalanceA,
|
||||
minimumBalanceA: minimumBalanceA,
|
||||
maximumBalanceA: maximumBalanceA,
|
||||
@@ -1605,7 +1722,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> callback -> recordsArray.length = " + recordsArray.length); }
|
||||
|
||||
callback(tradingSystem, recordsArray, conditionsArray, strategiesArray, tradesArray, lastObjectsArray);
|
||||
callback(tradingSystem, executionArray, recordsArray, conditionsArray, strategiesArray, tradesArray, lastObjectsArray);
|
||||
|
||||
function getElement(pArray, begin, end) {
|
||||
|
||||
@@ -1620,11 +1737,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
}
|
||||
}
|
||||
|
||||
element = {
|
||||
direction: 'unknown',
|
||||
slope: 'unknown'
|
||||
};
|
||||
return element;
|
||||
return
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
@@ -1653,17 +1766,17 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
if (previous !== undefined) {
|
||||
|
||||
if (previous._15 > LRC._15) { LRC.direction15 = 'down'; }
|
||||
if (previous._15 < LRC._15) { LRC.direction15 = 'up'; }
|
||||
if (previous._15 === LRC._15) { LRC.direction15 = 'side'; }
|
||||
if (previous._15 > LRC._15) { LRC.direction15 = 'Down'; }
|
||||
if (previous._15 < LRC._15) { LRC.direction15 = 'Up'; }
|
||||
if (previous._15 === LRC._15) { LRC.direction15 = 'Side'; }
|
||||
|
||||
if (previous._30 > LRC._30) { LRC.direction30 = 'down'; }
|
||||
if (previous._30 < LRC._30) { LRC.direction30 = 'up'; }
|
||||
if (previous._30 === LRC._30) { LRC.direction30 = 'side'; }
|
||||
if (previous._30 > LRC._30) { LRC.direction30 = 'Down'; }
|
||||
if (previous._30 < LRC._30) { LRC.direction30 = 'Up'; }
|
||||
if (previous._30 === LRC._30) { LRC.direction30 = 'Side'; }
|
||||
|
||||
if (previous._60 > LRC._60) { LRC.direction60 = 'down'; }
|
||||
if (previous._60 < LRC._60) { LRC.direction60 = 'up'; }
|
||||
if (previous._60 === LRC._60) { LRC.direction60 = 'side'; }
|
||||
if (previous._60 > LRC._60) { LRC.direction60 = 'Down'; }
|
||||
if (previous._60 < LRC._60) { LRC.direction60 = 'Up'; }
|
||||
if (previous._60 === LRC._60) { LRC.direction60 = 'Side'; }
|
||||
|
||||
}
|
||||
|
||||
@@ -1700,9 +1813,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
if (previous !== undefined) {
|
||||
|
||||
if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; }
|
||||
if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; }
|
||||
if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; }
|
||||
if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'Down'; }
|
||||
if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'Up'; }
|
||||
if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'Side'; }
|
||||
|
||||
}
|
||||
|
||||
@@ -1739,9 +1852,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
if (previous !== undefined) {
|
||||
|
||||
if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; }
|
||||
if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; }
|
||||
if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; }
|
||||
if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'Down'; }
|
||||
if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'Up'; }
|
||||
if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'Side'; }
|
||||
|
||||
}
|
||||
|
||||
@@ -1772,11 +1885,7 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
begin: dataFile[i][0],
|
||||
end: dataFile[i][1],
|
||||
direction: dataFile[i][2],
|
||||
period: dataFile[i][3],
|
||||
firstMovingAverage: dataFile[i][4],
|
||||
lastMovingAverage: dataFile[i][5],
|
||||
firstDeviation: dataFile[i][6],
|
||||
lastDeviation: dataFile[i][7]
|
||||
period: dataFile[i][3]
|
||||
};
|
||||
|
||||
bollingerChannel.previous = previous;
|
||||
@@ -1856,9 +1965,9 @@ exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
candle.begin = dataFile[i][4];
|
||||
candle.end = dataFile[i][5];
|
||||
|
||||
if (candle.open > candle.close) { candle.direction = 'down'; }
|
||||
if (candle.open < candle.close) { candle.direction = 'up'; }
|
||||
if (candle.open === candle.close) { candle.direction = 'side'; }
|
||||
if (candle.open > candle.close) { candle.direction = 'Down'; }
|
||||
if (candle.open < candle.close) { candle.direction = 'Up'; }
|
||||
if (candle.open === candle.close) { candle.direction = 'Side'; }
|
||||
|
||||
candle.previous = previous;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
const MODULE_NAME = "User Bot";
|
||||
|
||||
const EXECUTION_FOLDER_NAME = "Trading-Execution";
|
||||
const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation";
|
||||
const CONDITIONS_FOLDER_NAME = "Simulation-Conditions";
|
||||
const STRATEGIES_FOLDER_NAME = "Simulation-Strategies";
|
||||
@@ -104,16 +105,91 @@
|
||||
writeFiles,
|
||||
callBackFunction)
|
||||
|
||||
function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) {
|
||||
function writeFiles(pTradingSystem, pExecutionArray, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) {
|
||||
|
||||
tradingSystem = pTradingSystem
|
||||
executionArray = pExecutionArray
|
||||
recordsArray = pRecordsArray
|
||||
conditionsArray = pConditionsArray
|
||||
strategiesArray = pStrategiesArray
|
||||
tradesArray = pTradesArray
|
||||
lastObjectsArray = pLastObjectsArray
|
||||
|
||||
writeRecordsFile()
|
||||
writeExecutionFile()
|
||||
}
|
||||
|
||||
function writeExecutionFile() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < executionArray.length; i++) {
|
||||
|
||||
let record = executionArray[i];
|
||||
|
||||
/* Will only add to the file the records of the current day */
|
||||
|
||||
if (record.begin < currentDay.valueOf()) { continue; }
|
||||
|
||||
fileContent = fileContent + separator + '[' +
|
||||
record.begin + "," +
|
||||
record.end + "," +
|
||||
JSON.stringify(record.executionRecord) + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
fileRecordCounter++;
|
||||
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
|
||||
let fileName = '' + market.assetA + '_' + market.assetB + '.json';
|
||||
|
||||
let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
||||
let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> fileContent = " + fileContent); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB);
|
||||
|
||||
callBackFunction(err);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
writeRecordsFile();
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeRecordsFile() {
|
||||
@@ -161,7 +237,7 @@
|
||||
record.takeProfit + "," +
|
||||
record.stopLossPhase + "," +
|
||||
record.takeProfitPhase + "," +
|
||||
JSON.stringify(record.orderRecord) + "," +
|
||||
JSON.stringify(record.executionRecord) + "," +
|
||||
record.positionSize + "," +
|
||||
record.initialBalanceA + "," +
|
||||
record.minimumBalanceA + "," +
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
const MODULE_NAME = "User Bot";
|
||||
|
||||
const EXECUTION_FOLDER_NAME = "Trading-Execution";
|
||||
const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation";
|
||||
const CONDITIONS_FOLDER_NAME = "Simulation-Conditions";
|
||||
const STRATEGIES_FOLDER_NAME = "Simulation-Strategies";
|
||||
@@ -104,16 +105,86 @@
|
||||
writeFiles,
|
||||
callBackFunction)
|
||||
|
||||
function writeFiles(pTradingSystem, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) {
|
||||
function writeFiles(pTradingSystem, pExecutionArray, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) {
|
||||
|
||||
tradingSystem = pTradingSystem
|
||||
executionArray = pExecutionArray
|
||||
recordsArray = pRecordsArray
|
||||
conditionsArray = pConditionsArray
|
||||
strategiesArray = pStrategiesArray
|
||||
tradesArray = pTradesArray
|
||||
lastObjectsArray = pLastObjectsArray
|
||||
|
||||
writeRecordsFile()
|
||||
writeExecutionFile()
|
||||
}
|
||||
|
||||
function writeExecutionFile() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < executionArray.length; i++) {
|
||||
|
||||
let record = executionArray[i];
|
||||
|
||||
fileContent = fileContent + separator + '[' +
|
||||
record.begin + "," +
|
||||
record.end + "," +
|
||||
JSON.stringify(record.executionRecord) + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
fileRecordCounter++;
|
||||
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = '' + market.assetA + '_' + market.assetB + '.json';
|
||||
|
||||
let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
||||
let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> fileContent = " + fileContent); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB);
|
||||
|
||||
callBackFunction(err);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
writeRecordsFile();
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeRecordsFile() {
|
||||
@@ -157,7 +228,7 @@
|
||||
record.takeProfit + "," +
|
||||
record.stopLossPhase + "," +
|
||||
record.takeProfitPhase + "," +
|
||||
JSON.stringify(record.orderRecord) + "," +
|
||||
JSON.stringify(record.executionRecord) + "," +
|
||||
record.positionSize + "," +
|
||||
record.initialBalanceA + "," +
|
||||
record.minimumBalanceA + "," +
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
},
|
||||
"product": "Bollinger-Channels",
|
||||
"product": "Bollinger-Standard-Channels",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
},
|
||||
@@ -90,7 +90,7 @@
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
},
|
||||
"product": "Bollinger-Sub-Channels",
|
||||
"product": "Bollinger-Standard-Sub-Channels",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
},
|
||||
@@ -166,7 +166,7 @@
|
||||
},
|
||||
"product": "LRC-Points",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
},
|
||||
{
|
||||
"devTeam": "AAMasters",
|
||||
@@ -177,7 +177,7 @@
|
||||
},
|
||||
"product": "Percentage-Bandwidth",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
},
|
||||
{
|
||||
"devTeam": "AAMasters",
|
||||
@@ -188,7 +188,7 @@
|
||||
},
|
||||
"product": "Bollinger-Bands",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
},
|
||||
{
|
||||
"devTeam": "AAMasters",
|
||||
@@ -197,9 +197,9 @@
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
},
|
||||
"product": "Bollinger-Channels",
|
||||
"product": "Bollinger-Standard-Channels",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
},
|
||||
{
|
||||
"devTeam": "AAMasters",
|
||||
@@ -208,9 +208,9 @@
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
},
|
||||
"product": "Bollinger-Sub-Channels",
|
||||
"product": "Bollinger-Standard-Sub-Channels",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
},
|
||||
{
|
||||
"devTeam": "AAMasters",
|
||||
@@ -221,7 +221,7 @@
|
||||
},
|
||||
"product": "Candles",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
exports.newUserBot = function newUserBot(bot, logger) {
|
||||
|
||||
// Variable used for logs, which will be passed to the logger instance
|
||||
const MODULE_NAME = 'User Bot'
|
||||
@@ -42,12 +42,12 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
throw new Error("Execution Parameter Data Set not defined.")
|
||||
}
|
||||
|
||||
let key = bot.devTeam + '-simulator-' + bot.codeName + '-Trading-Simulation-' + bot.dataSet + '-dataSet.V1'
|
||||
let key = bot.devTeam + '-simulator-' + bot.codeName + '-Trading-Execution-' + bot.dataSet + '-dataSet.V1'
|
||||
fileStorage = assistant.dataDependencies.dataSets.get(key)
|
||||
|
||||
if (fileStorage !== undefined){
|
||||
if (fileStorage !== undefined) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE)
|
||||
}else{
|
||||
} else {
|
||||
logError('initialize -> Failed to initialize storage. Key not found:' + key)
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
@@ -90,34 +90,89 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
})
|
||||
}
|
||||
|
||||
function getValueFromPreviousExecution(key) {
|
||||
let value = assistant.remindMeOf(key)
|
||||
if (value === undefined)
|
||||
value = 0
|
||||
return value
|
||||
}
|
||||
|
||||
async function executorLogic() {
|
||||
try {
|
||||
let indicatorFileContent = await getIndicatorFile()
|
||||
let simulatorEngineMessage = getSimulatorEngineMessageFromFile(indicatorFileContent)
|
||||
let autopilotResponse = await getAutopilot()
|
||||
|
||||
let stopLoss, takeProfit, receivedMessageId
|
||||
if (simulatorEngineMessage === undefined) {
|
||||
logWarn('start -> Indicator message not found.')
|
||||
throw global.DEFAULT_RETRY_RESPONSE
|
||||
}
|
||||
logWarn('start -> Simulator message not available. Will proceed to check SL and TP from previous execution.')
|
||||
stopLoss = getValueFromPreviousExecution('lastStopLoss')
|
||||
takeProfit = getValueFromPreviousExecution('lastTakeProfit')
|
||||
receivedMessageId = 0
|
||||
} else {
|
||||
logInfo('Processing simulator record: ' + JSON.stringify(simulatorEngineMessage))
|
||||
receivedMessageId = simulatorEngineMessage.id
|
||||
|
||||
logInfo('Processing indicator message: ' + JSON.stringify(simulatorEngineMessage))
|
||||
// Verify if there is an inconsistent state between the simulator and executor
|
||||
let isATradeOpen = (getValueFromPreviousExecution('lastSimulatorEngineMessageId') > 0)
|
||||
let isMessageAHeartBeat = (simulatorEngineMessage.messageType === MESSAGE_TYPE.HeartBeat)
|
||||
if (isATradeOpen && isMessageAHeartBeat) {
|
||||
logWarn('An inconsisten state was detected: there is an open trade and a close trade was expected.')
|
||||
let skippedMessageOrderClose = getSkippedMessageOrderClose(indicatorFileContent)
|
||||
if (skippedMessageOrderClose === undefined) {
|
||||
logWarn('There was not a Skipped Message Order Close. Closing the position the best possible.')
|
||||
stopLoss = assistant.getMarketRate()
|
||||
takeProfit = assistant.getMarketRate()
|
||||
} else {
|
||||
let lastSimulatorEngineMessageId = getValueFromPreviousExecution('lastSimulatorEngineMessageId')
|
||||
if (skippedMessageOrderClose.id > lastSimulatorEngineMessageId) {
|
||||
logWarn('The Skipped Message Order Close was found and using it to set the SL and TP.')
|
||||
isMessageAnOrderClose = (simulatorEngineMessage.messageType === MESSAGE_TYPE.OrderClose)
|
||||
isStopLoss = (simulatorEngineMessage.order.exitOutcome === ORDER_EXIT_OUTCOME.StopLoss)
|
||||
isTakeProfit = (simulatorEngineMessage.order.exitOutcome === ORDER_EXIT_OUTCOME.StopLoss)
|
||||
} else {
|
||||
logWarn('One Message Order Close was found but is older than the Open Order. Closing the position the best possible.')
|
||||
stopLoss = assistant.getMarketRate()
|
||||
takeProfit = assistant.getMarketRate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validations to check the sync state between the simulator and executor
|
||||
let isMessageAnOrderUpdate = (simulatorEngineMessage.messageType === MESSAGE_TYPE.OrderUpdate)
|
||||
let isMessageAnOrderClose = (simulatorEngineMessage.messageType === MESSAGE_TYPE.OrderClose)
|
||||
let isStopLoss = (simulatorEngineMessage.order.exitOutcome === ORDER_EXIT_OUTCOME.StopLoss)
|
||||
let isTakeProfit = (simulatorEngineMessage.order.exitOutcome === ORDER_EXIT_OUTCOME.StopLoss)
|
||||
|
||||
if (isMessageAnOrderUpdate) {
|
||||
stopLoss = simulatorEngineMessage.order.stop
|
||||
takeProfit = simulatorEngineMessage.order.takeProfit
|
||||
} else if (isMessageAnOrderClose && isStopLoss) {
|
||||
stopLoss = assistant.getMarketRate()
|
||||
takeProfit = 0
|
||||
} else if (isMessageAnOrderClose && isTakeProfit) {
|
||||
stopLoss = 0
|
||||
takeProfit = assistant.getMarketRate()
|
||||
}
|
||||
assistant.rememberThis('lastStopLoss', stopLoss)
|
||||
assistant.rememberThis('lastTakeProfit', takeProfit)
|
||||
}
|
||||
|
||||
// Checking Stop Loss
|
||||
let assetABalance = assistant.getAvailableBalance().assetA
|
||||
let currentRate = assistant.getMarketRate()
|
||||
|
||||
if (simulatorEngineMessage !== undefined && assetABalance > 0 && currentRate >= simulatorEngineMessage.order.stop) {
|
||||
if (stopLoss > 0 && assetABalance > 0 && currentRate >= stopLoss) {
|
||||
logInfo('Closing trade with Stop Loss.')
|
||||
try {
|
||||
let position = await createBuyPosition(currentRate)
|
||||
|
||||
let simulatorExecutorMessage = buildBasicSimulatorExecutorMessage()
|
||||
simulatorExecutorMessage.id = position.id
|
||||
simulatorExecutorMessage.id = receivedMessageId
|
||||
simulatorExecutorMessage.order.id = position.id
|
||||
simulatorExecutorMessage.order.rate = currentRate
|
||||
simulatorExecutorMessage.order.stop = simulatorEngineMessage.order.stop
|
||||
simulatorExecutorMessage.order.takeProfit = simulatorEngineMessage.order.takeProfit
|
||||
simulatorExecutorMessage.order.stop = stopLoss
|
||||
simulatorExecutorMessage.order.takeProfit = takeProfit
|
||||
simulatorExecutorMessage.order.direction = ORDER_DIRECTION.Buy
|
||||
simulatorExecutorMessage.order.size = assetABalance
|
||||
simulatorExecutorMessage.order.status = ORDER_STATUS.Placed
|
||||
@@ -125,13 +180,17 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
|
||||
let message = createMessageFromObject(simulatorExecutorMessage)
|
||||
assistant.addExtraData(message)
|
||||
assistant.rememberThis('lastSimulatorEngineMessageId', 0)
|
||||
assistant.rememberThis('lastStopLoss', 0)
|
||||
assistant.rememberThis('lastTakeProfit', 0)
|
||||
} catch (error) {
|
||||
let simulatorExecutorMessage = buildBasicSimulatorExecutorMessage()
|
||||
simulatorExecutorMessage.id = receivedMessageId
|
||||
simulatorExecutorMessage.from = MESSAGE_ENTITY.TradingAssistant
|
||||
simulatorExecutorMessage.to = MESSAGE_ENTITY.SimulationExecutor
|
||||
simulatorExecutorMessage.order.rate = position.rate
|
||||
simulatorExecutorMessage.order.stop = simulatorEngineMessage.order.stop
|
||||
simulatorExecutorMessage.order.takeProfit = simulatorEngineMessage.order.takeProfit
|
||||
simulatorExecutorMessage.order.stop = stopLoss
|
||||
simulatorExecutorMessage.order.takeProfit = takeProfit
|
||||
simulatorExecutorMessage.order.direction = ORDER_DIRECTION.Buy
|
||||
simulatorExecutorMessage.order.size = assetABalance
|
||||
simulatorExecutorMessage.order.status = ORDER_STATUS.Rejected
|
||||
@@ -144,17 +203,17 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
}
|
||||
|
||||
// Checking Take Profits
|
||||
if (simulatorEngineMessage !== undefined && assetABalance > 0 && currentRate <= simulatorEngineMessage.order.takeProfit) {
|
||||
logInfo('Closing trade with Take Profits.')
|
||||
if (takeProfit > 0 && assetABalance > 0 && currentRate <= takeProfit) {
|
||||
logInfo('Closing trade with Take Profit.')
|
||||
try {
|
||||
let position = await createBuyPosition(currentRate, assetABalance)
|
||||
|
||||
let simulatorExecutorMessage = buildBasicSimulatorExecutorMessage()
|
||||
simulatorExecutorMessage.id = position.id
|
||||
simulatorExecutorMessage.id = receivedMessageId
|
||||
simulatorExecutorMessage.order.id = position.id
|
||||
simulatorExecutorMessage.order.rate = currentRate
|
||||
simulatorExecutorMessage.order.stop = simulatorEngineMessage.order.stop
|
||||
simulatorExecutorMessage.order.takeProfit = simulatorEngineMessage.order.takeProfit
|
||||
simulatorExecutorMessage.order.stop = stopLoss
|
||||
simulatorExecutorMessage.order.takeProfit = takeProfit
|
||||
simulatorExecutorMessage.order.direction = ORDER_DIRECTION.Buy
|
||||
simulatorExecutorMessage.order.size = assetABalance
|
||||
simulatorExecutorMessage.order.status = ORDER_STATUS.Placed
|
||||
@@ -162,16 +221,21 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
|
||||
let message = createMessageFromObject(simulatorExecutorMessage)
|
||||
assistant.addExtraData(message)
|
||||
assistant.rememberThis('lastSimulatorEngineMessageId', 0)
|
||||
assistant.rememberThis('lastStopLoss', 0)
|
||||
assistant.rememberThis('lastTakeProfit', 0)
|
||||
} catch (error) {
|
||||
let simulatorExecutorMessage = buildBasicSimulatorExecutorMessage()
|
||||
simulatorExecutorMessage.id = receivedMessageId
|
||||
simulatorExecutorMessage.from = MESSAGE_ENTITY.TradingAssistant
|
||||
simulatorExecutorMessage.to = MESSAGE_ENTITY.SimulationExecutor
|
||||
simulatorExecutorMessage.order.rate = currentRate
|
||||
simulatorExecutorMessage.order.stop = simulatorEngineMessage.order.stop
|
||||
simulatorExecutorMessage.order.takeProfit = simulatorEngineMessage.order.takeProfit
|
||||
simulatorExecutorMessage.order.stop = stopLoss
|
||||
simulatorExecutorMessage.order.takeProfit = takeProfit
|
||||
simulatorExecutorMessage.order.direction = ORDER_DIRECTION.Buy
|
||||
simulatorExecutorMessage.order.size = assetABalance
|
||||
simulatorExecutorMessage.order.status = ORDER_STATUS.Rejected
|
||||
simulatorExecutorMessage.order.statusDetails = error.message
|
||||
|
||||
let message = createMessageFromObject(simulatorExecutorMessage)
|
||||
assistant.addExtraData(message)
|
||||
@@ -180,13 +244,16 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
}
|
||||
}
|
||||
|
||||
if (autopilotResponse.autopilot || autopilotControl) {
|
||||
await manageCloneInAutopilotOn(simulatorEngineMessage)
|
||||
} else {
|
||||
await manageCloneInAutopilotOff(simulatorEngineMessage)
|
||||
if (simulatorEngineMessage !== undefined) {
|
||||
if (autopilotResponse.autopilot || autopilotControl) {
|
||||
await manageCloneInAutopilotOn(simulatorEngineMessage)
|
||||
} else {
|
||||
await manageCloneInAutopilotOff(simulatorEngineMessage)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.stack) logError(JSON.stringify(error.stack))
|
||||
logError('Error on executorLogic: ' + error)
|
||||
logError('Stack: ' + JSON.stringify(error.stack))
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -198,10 +265,16 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
if (simulatorEngineMessage.messageType === MESSAGE_TYPE.Order
|
||||
&& simulatorEngineMessage.order.direction === ORDER_DIRECTION.Sell) {
|
||||
|
||||
let lastSimulatorEngineMessageId = getValueFromPreviousExecution('lastSimulatorEngineMessageId')
|
||||
if (lastSimulatorEngineMessageId >= simulatorEngineMessage.id) {
|
||||
logInfo("manageCloneInAutopilotOn -> Order message was previously processed.")
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
let position = await createSellPosition(currentRate, assetBBalance)
|
||||
let simulatorExecutorMessage = buildBasicSimulatorExecutorMessage()
|
||||
simulatorExecutorMessage.id = position.id
|
||||
simulatorExecutorMessage.id = simulatorEngineMessage.id
|
||||
simulatorExecutorMessage.order.id = position.id
|
||||
simulatorExecutorMessage.order.rate = currentRate
|
||||
simulatorExecutorMessage.order.stop = simulatorEngineMessage.order.stop
|
||||
@@ -211,8 +284,12 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
|
||||
let message = createMessageFromObject(simulatorExecutorMessage)
|
||||
assistant.addExtraData(message)
|
||||
assistant.rememberThis('lastSimulatorEngineMessageId', simulatorEngineMessage.id)
|
||||
assistant.rememberThis('lastStopLoss', simulatorEngineMessage.order.stop)
|
||||
assistant.rememberThis('lastTakeProfit', simulatorEngineMessage.order.takeProfit)
|
||||
} catch (error) {
|
||||
let simulatorExecutorMessage = buildBasicSimulatorExecutorMessage()
|
||||
simulatorExecutorMessage.id = receivedMessageId
|
||||
simulatorExecutorMessage.from = MESSAGE_ENTITY.TradingAssistant
|
||||
simulatorExecutorMessage.to = MESSAGE_ENTITY.SimulationExecutor
|
||||
simulatorExecutorMessage.messageType = MESSAGE_TYPE.Order
|
||||
@@ -222,6 +299,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
simulatorExecutorMessage.order.direction = ORDER_DIRECTION.Sell
|
||||
simulatorExecutorMessage.order.size = assetBBalance
|
||||
simulatorExecutorMessage.order.status = ORDER_STATUS.Rejected
|
||||
simulatorExecutorMessage.order.statusDetails = error.message
|
||||
|
||||
let message = createMessageFromObject(simulatorExecutorMessage)
|
||||
assistant.addExtraData(message)
|
||||
@@ -247,7 +325,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
|
||||
// 1) Save audit containing what we received from the cockpit
|
||||
let simulatorExecutorMessage = buildBasicSimulatorExecutorMessage()
|
||||
simulatorExecutorMessage.id = 0
|
||||
simulatorExecutorMessage.id = simulatorEngineMessage.id
|
||||
simulatorExecutorMessage.from = MESSAGE_ENTITY.TradingCokpit
|
||||
simulatorExecutorMessage.to = MESSAGE_ENTITY.SimulationExecutor
|
||||
simulatorExecutorMessage.order = acceptedSignal.orderData // we save the order as received
|
||||
@@ -260,7 +338,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
|
||||
// 3) Save the audit of the order placed
|
||||
simulatorExecutorMessage = buildBasicSimulatorExecutorMessage()
|
||||
simulatorExecutorMessage.id = position.id
|
||||
simulatorExecutorMessage.id = simulatorEngineMessage.id
|
||||
simulatorExecutorMessage.from = MESSAGE_ENTITY.SimulationExecutor
|
||||
simulatorExecutorMessage.to = MESSAGE_ENTITY.TradingAssistant
|
||||
simulatorExecutorMessage.dateTime = position.date
|
||||
@@ -282,12 +360,13 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
} catch (error) {
|
||||
// Update the cockpit with the error
|
||||
let simulatorExecutorMessage = buildBasicSimulatorExecutorMessage()
|
||||
simulatorExecutorMessage.id = 0
|
||||
simulatorExecutorMessage.id = simulatorEngineMessage.id
|
||||
simulatorExecutorMessage.from = MESSAGE_ENTITY.SimulationExecutor
|
||||
simulatorExecutorMessage.to = MESSAGE_ENTITY.TradingCokpit
|
||||
simulatorExecutorMessage.messageType = MESSAGE_TYPE.Order
|
||||
simulatorExecutorMessage.dateTime = bot.processDatetime.valueOf()
|
||||
simulatorExecutorMessage.order.status = ORDER_STATUS.Rejected
|
||||
simulatorExecutorMessage.order.statusDetails = error.message
|
||||
|
||||
simulatorExecutorMessage.order = acceptedSignal.order
|
||||
|
||||
@@ -380,7 +459,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
|
||||
// 2) Save the audit message for the received info from Trading Simulator
|
||||
let simulatorExecutorMessage = buildBasicSimulatorExecutorMessage()
|
||||
simulatorExecutorMessage.id = 0
|
||||
simulatorExecutorMessage.id = simulatorEngineMessage.id
|
||||
simulatorExecutorMessage.to = MESSAGE_ENTITY.TradingCokpit
|
||||
simulatorExecutorMessage.messageType = MESSAGE_TYPE.Order
|
||||
simulatorExecutorMessage.order.id = 0
|
||||
@@ -499,17 +578,17 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
|
||||
// Storage functions
|
||||
async function getIndicatorFile() {
|
||||
logInfo('getIndicatorFile -> Entering function.')
|
||||
logInfo('getIndicatorFile -> Entering function. ' + bot.processDatetime.toISOString())
|
||||
|
||||
let filePath
|
||||
if (bot.processes[0].timePeriod > 2700000) {
|
||||
// Market Files
|
||||
filePath = 'Trading-Simulation/' + bot.dataSet + '/' + bot.timePeriodFileStorage
|
||||
filePath = 'Trading-Execution/' + bot.dataSet + '/' + bot.timePeriodFileStorage
|
||||
} else {
|
||||
// Daily Files
|
||||
let dateTime = bot.processDatetime
|
||||
let datePath = dateTime.getUTCFullYear() + '/' + pad(dateTime.getUTCMonth() + 1, 2) + '/' + pad(dateTime.getUTCDate(), 2)
|
||||
filePath = 'Trading-Simulation/' + bot.dataSet + '/' + bot.timePeriodFileStorage + '/' + datePath
|
||||
filePath = 'Trading-Execution/' + bot.dataSet + '/' + bot.timePeriodFileStorage + '/' + datePath
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -536,18 +615,18 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
if (bot.processDatetime.valueOf() <= lastAvailableDateTime || !isExecutionToday()) {
|
||||
for (let i = 0; i < indicatorFileContent.length; i++) {
|
||||
if (bot.processDatetime.valueOf() >= indicatorFileContent[i][0] && bot.processDatetime.valueOf() < indicatorFileContent[i][1]) {
|
||||
return getMessage(indicatorFileContent[i][25])
|
||||
return getMessage(indicatorFileContent[i][2])
|
||||
}
|
||||
}
|
||||
|
||||
logWarn('getSimulatorEngineMessageFromFile -> The indicator message was not found at time: ' + bot.processDatetime.valueOf())
|
||||
} else {
|
||||
// Running live we will process last available Indicator Message only if it's delayed 25 minutes top
|
||||
let maxTolerance = 120 * 60 * 1000
|
||||
// Running live we will process last available Indicator Message only if it's delayed 10 minutes top
|
||||
let maxTolerance = 10 * 60 * 1000
|
||||
if (bot.processDatetime.valueOf() <= (lastAvailableDateTime + maxTolerance)) {
|
||||
return getMessage(indicatorFileContent[lastIndexIndicatorFile][25])
|
||||
return getMessage(indicatorFileContent[lastIndexIndicatorFile][2])
|
||||
} else {
|
||||
logWarn('getSimulatorEngineMessageFromFile -> Last available indicator older than 2 hours. Skipping execution.')
|
||||
logWarn('getSimulatorEngineMessageFromFile -> Last available indicator older than 10 minutes.')
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -556,6 +635,22 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
}
|
||||
}
|
||||
|
||||
function getSkippedMessageOrderClose(indicatorFileContent) {
|
||||
try {
|
||||
let lastIndexIndicatorFile = indicatorFileContent.length - 1
|
||||
|
||||
for (let i = lastIndexIndicatorFile; i >= 0; i--) {
|
||||
let simulatorMessage = getMessage(indicatorFileContent[i][2])
|
||||
if (simulatorMessage.messageType === MESSAGE_TYPE.OrderClose) {
|
||||
return simulatorMessage
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logError('getSkippedMessageOrderClose -> error = ' + error.message)
|
||||
throw global.DEFAULT_RETRY_RESPONSE
|
||||
}
|
||||
}
|
||||
|
||||
// Helper Functions
|
||||
function isExecutionToday() {
|
||||
let localDate = new Date()
|
||||
@@ -720,7 +815,9 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
fileStorage.getTextFile[util.promisify.custom] = n => new Promise((resolve, reject) => {
|
||||
fileStorage.getTextFile(containerName, blobName, (result, fileContent) => {
|
||||
if (result !== global.DEFAULT_OK_RESPONSE) {
|
||||
console.log('[WARN] getFileContent -> The indicator dependency is not ready. Will retry later.')
|
||||
let errorMessage = '[WARN] getFileContent -> The indicator dependency is not ready. Will retry later.'
|
||||
console.log(errorMessage)
|
||||
logWarn(errorMessage)
|
||||
reject(global.DEFAULT_RETRY_RESPONSE)
|
||||
} else {
|
||||
resolve(fileContent)
|
||||
@@ -747,16 +844,18 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS_MODULE) {
|
||||
simulatorExecutorMessage.dateTime = bot.processDatetime.valueOf()
|
||||
|
||||
simulatorExecutorMessage.order = {}
|
||||
simulatorExecutorMessage.order.id = 0
|
||||
simulatorExecutorMessage.order.dateTime = bot.processDatetime.valueOf()
|
||||
simulatorExecutorMessage.order.creator = ORDER_CREATOR.SimulationEngine
|
||||
simulatorExecutorMessage.order.owner = ORDER_OWNER.User
|
||||
simulatorExecutorMessage.order.exchange = global.EXCHANGE_NAME
|
||||
simulatorExecutorMessage.order.market = global.MARKET.name
|
||||
simulatorExecutorMessage.order.market = global.MARKET.assetA + '_' + global.MARKET.assetB
|
||||
simulatorExecutorMessage.order.marginEnabled = ORDER_MARGIN_ENABLED.False
|
||||
simulatorExecutorMessage.order.type = ORDER_TYPE.Limit
|
||||
simulatorExecutorMessage.order.status = ORDER_STATUS.Placed
|
||||
simulatorExecutorMessage.order.sizeFilled = 0
|
||||
simulatorExecutorMessage.order.exitOutcome = ''
|
||||
simulatorExecutorMessage.order.statusMessage = ''
|
||||
|
||||
return simulatorExecutorMessage
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"minor": 0,
|
||||
"patch": 0
|
||||
},
|
||||
"devTeam": "aavikings",
|
||||
"devTeam": "vikings",
|
||||
"profilePicture": "bumblebee.png",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"processes": [
|
||||
@@ -73,7 +73,7 @@
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
},
|
||||
"product": "Trading-Simulation",
|
||||
"product": "Trading-Execution",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
},
|
||||
@@ -84,7 +84,7 @@
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
},
|
||||
"product": "Trading-Simulation",
|
||||
"product": "Trading-Execution",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
}
|
||||
@@ -101,27 +101,7 @@
|
||||
{
|
||||
"codeName": "Oficial History",
|
||||
"type": "File Sequence",
|
||||
"validPeriods": [
|
||||
"24-hs",
|
||||
"12-hs",
|
||||
"08-hs",
|
||||
"06-hs",
|
||||
"04-hs",
|
||||
"03-hs",
|
||||
"02-hs",
|
||||
"01-hs",
|
||||
"45-min",
|
||||
"40-min",
|
||||
"30-min",
|
||||
"20-min",
|
||||
"15-min",
|
||||
"10-min",
|
||||
"05-min",
|
||||
"04-min",
|
||||
"03-min",
|
||||
"02-min",
|
||||
"01-min"
|
||||
],
|
||||
"validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs", "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ],
|
||||
"filePath": "@DevTeam/@Bot.1.0/AACloud.1.1/Poloniex/dataSet.V1/Output/Trading-Process",
|
||||
"fileName": "Execution.History.Live.@Sequence.json"
|
||||
}
|
||||
@@ -131,11 +111,11 @@
|
||||
"name": "Poloniex"
|
||||
}
|
||||
],
|
||||
"plotter": {
|
||||
"devTeam": "AAMasters",
|
||||
"codeName": "PlottersTradingSimulation",
|
||||
"moduleName": "SimulationExecution"
|
||||
}
|
||||
"plotter": {
|
||||
"devTeam": "AAMasters",
|
||||
"codeName": "PlottersTradingSimulation",
|
||||
"moduleName": "SimulationExecution"
|
||||
}
|
||||
},
|
||||
{
|
||||
"codeName": "Backtest Trading History",
|
||||
@@ -146,27 +126,7 @@
|
||||
{
|
||||
"codeName": "Backtest History",
|
||||
"type": "File Sequence",
|
||||
"validPeriods": [
|
||||
"24-hs",
|
||||
"12-hs",
|
||||
"08-hs",
|
||||
"06-hs",
|
||||
"04-hs",
|
||||
"03-hs",
|
||||
"02-hs",
|
||||
"01-hs",
|
||||
"45-min",
|
||||
"40-min",
|
||||
"30-min",
|
||||
"20-min",
|
||||
"15-min",
|
||||
"10-min",
|
||||
"05-min",
|
||||
"04-min",
|
||||
"03-min",
|
||||
"02-min",
|
||||
"01-min"
|
||||
],
|
||||
"validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs", "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ],
|
||||
"filePath": "@DevTeam/@Bot.1.0/AACloud.1.1/Poloniex/dataSet.V1/Output/Trading-Process",
|
||||
"fileName": "Execution.History.Backtest.@Sequence.json"
|
||||
}
|
||||
@@ -176,11 +136,11 @@
|
||||
"name": "Poloniex"
|
||||
}
|
||||
],
|
||||
"plotter": {
|
||||
"devTeam": "AAMasters",
|
||||
"codeName": "PlottersTradingSimulation",
|
||||
"moduleName": "SimulationExecution"
|
||||
}
|
||||
"plotter": {
|
||||
"devTeam": "AAMasters",
|
||||
"codeName": "PlottersTradingSimulation",
|
||||
"moduleName": "SimulationExecution"
|
||||
}
|
||||
},
|
||||
{
|
||||
"codeName": "Competition Trading History",
|
||||
@@ -191,27 +151,7 @@
|
||||
{
|
||||
"codeName": "Competition History",
|
||||
"type": "File Sequence",
|
||||
"validPeriods": [
|
||||
"24-hs",
|
||||
"12-hs",
|
||||
"08-hs",
|
||||
"06-hs",
|
||||
"04-hs",
|
||||
"03-hs",
|
||||
"02-hs",
|
||||
"01-hs",
|
||||
"45-min",
|
||||
"40-min",
|
||||
"30-min",
|
||||
"20-min",
|
||||
"15-min",
|
||||
"10-min",
|
||||
"05-min",
|
||||
"04-min",
|
||||
"03-min",
|
||||
"02-min",
|
||||
"01-min"
|
||||
],
|
||||
"validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs", "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ],
|
||||
"filePath": "@DevTeam/@Bot.1.0/AACloud.1.1/Poloniex/dataSet.V1/Output/Trading-Process",
|
||||
"fileName": "Execution.History.Competition.@Sequence.json"
|
||||
}
|
||||
@@ -221,11 +161,11 @@
|
||||
"name": "Poloniex"
|
||||
}
|
||||
],
|
||||
"plotter": {
|
||||
"devTeam": "AAMasters",
|
||||
"codeName": "PlottersTradingSimulation",
|
||||
"moduleName": "SimulationExecution"
|
||||
}
|
||||
"plotter": {
|
||||
"devTeam": "AAMasters",
|
||||
"codeName": "PlottersTradingSimulation",
|
||||
"moduleName": "SimulationExecution"
|
||||
}
|
||||
}
|
||||
],
|
||||
"marketRateProvider": {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Ecosystem } from '../models'
|
||||
|
||||
let teamCache = new Map()
|
||||
export default async function getDevTeamHost(devTeamName, accessKey, ownerKey) {
|
||||
let host
|
||||
if (accessKey) {
|
||||
host = teamCache.get(devTeamName + '.accessKey')
|
||||
} else {
|
||||
host = teamCache.get(devTeamName + '.ownerKey')
|
||||
}
|
||||
if (host) {
|
||||
if (host.accessKey === accessKey || host.ownerKey === ownerKey) {
|
||||
return host
|
||||
}
|
||||
} else {
|
||||
let ecosystem = await Ecosystem.find()
|
||||
|
||||
for (var i = 0; i < ecosystem.length; i++) {
|
||||
for (var j = 0; j < ecosystem[i].devTeams.length; j++) {
|
||||
if (ecosystem[i].devTeams[j].codeName.toLowerCase() === devTeamName.toLowerCase()) {
|
||||
if (ecosystem[i].devTeams[j].host.accessKey === accessKey) {
|
||||
teamCache.set(devTeamName + '.accessKey', ecosystem[i].devTeams[j].host)
|
||||
return ecosystem[i].devTeams[j].host
|
||||
}
|
||||
if (ecosystem[i].devTeams[j].host.ownerKey === ownerKey) {
|
||||
teamCache.set(devTeamName + '.ownerKey', ecosystem[i].devTeams[j].host)
|
||||
return ecosystem[i].devTeams[j].host
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user