Merge pull request #8 from AAVikings/master

Updating templates
This commit is contained in:
benme authored and GitHub committed 2019-07-11 16:58:57 -03:00
commit af8367885a
15 files changed
+639 -286

No files matched your search

+4 -4
View File
@@ -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": [
{
+4
View File
@@ -31,6 +31,10 @@ const ecosystemSchema = new Schema({
accessKey: {
type: String,
required: false
},
ownerKey: {
type: String,
required: false
}
},
bots: [{
+1 -1
View File
@@ -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,
+3 -1
View File
@@ -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
}
+14 -2
View File
@@ -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)
+1 -1
View File
@@ -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) {
+16 -11
View File
@@ -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
+2 -1
View File
@@ -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 }
}),
});
+236 -127
View File
@@ -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"
}
]
}
+140 -41
View File
@@ -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": {
+34
View File
@@ -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
}
}
}
}
}
}