Merge pull request #307 from Superalgos/tutorials
Trading System Tutorials
No files matched your search
@@ -1,33 +0,0 @@
|
||||
|
||||
#PORT NUMBERS: If any of these ports are already in use by a different app, please pick a new number between 1 and 50000.
|
||||
HTTP_INTERFACE_PORT=34248
|
||||
WEB_SOCKETS_INTERFACE_PORT=18041
|
||||
|
||||
|
||||
# TASK MANAGER VARIABLES:
|
||||
|
||||
TASK_SERVER_PATH=./TaskServer
|
||||
|
||||
# TASK SERVER VARIABLES:
|
||||
|
||||
STORAGE_PATH=./Data-Storage
|
||||
|
||||
WRITE_LOGS_TO_FILES=true
|
||||
LOG_PATH=./Log-Files
|
||||
WEB_SERVER_URL=localhost
|
||||
|
||||
# WEB SERVER VARIABLES:
|
||||
|
||||
#Log options
|
||||
CONSOLE_LOG=false
|
||||
CONSOLE_ERROR_LOG=true
|
||||
LOG_FILE_CONTENT=false
|
||||
|
||||
PROJECTS_PATH=./Projects
|
||||
PATH_TO_UI=./UI
|
||||
PATH_TO_DATA_FILES=./UI/Data-Files/src
|
||||
PATH_TO_CLIENT=./Client/
|
||||
|
||||
DEFAULT_WORKSPACE_PATH=./Projects/Superalgos/Plugins/Workspaces
|
||||
MY_WORKSPACES_PATH=./My-Workspaces
|
||||
PATH_TO_FONTS=./Client/WebServer/Fonts
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
INTER_PROCESS_FILES_PATH=../Inter-Process-Files
|
||||
STORAGE_PATH=../Data-Storage
|
||||
|
||||
USE_KEYVAULT=false
|
||||
WRITE_LOGS_TO_FILES=true
|
||||
LOG_PATH=../Log-Files
|
||||
|
||||
WEB_SOCKETS_INTERFACE_PORT=18041
|
||||
WEB_SERVER_PORT=34248
|
||||
WEB_SERVER_URL=localhost
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -55,6 +55,7 @@
|
||||
Javier A., Gustavo J., Romina GS, Pedro P., Thais M., Andrey M., Loui M., Natalia M., Bashar A., Carlos V., Diego M.,
|
||||
Sebastian E., Bogdan P., Marko V., Igor S., Niksa K., Rodrigo M., Nicanor M., Alejandro P., Mateo H., Lan T., Leon A., Uroš R., Filip M., Vladimir J. and Pavle B.</p>
|
||||
<p><span class="red">You too can help grow and improve Superalgos. Become a contributor!</span></p>
|
||||
<p>If you like the project, please give it a <span class="red">star</span> and <span class="red">fork</span> it on Github. This helps developers find it on the search! </p>
|
||||
</div>
|
||||
<div id="masterApp"></div>
|
||||
<div id="canvasApp"></div>
|
||||
|
||||
@@ -344,3 +344,32 @@ kbd {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
code {
|
||||
color: #d9534f;
|
||||
background-color:rgb(200,200,200,0.1);
|
||||
padding: 2 0;
|
||||
font-size:110%;
|
||||
}
|
||||
|
||||
/* Tutorial Links */
|
||||
|
||||
a:link.tutorial-link {
|
||||
text-decoration: none;
|
||||
color: #31708f;
|
||||
}
|
||||
|
||||
a:visited.tutorial-link {
|
||||
text-decoration: none;
|
||||
color: #31708f;
|
||||
}
|
||||
|
||||
a:hover.tutorial-link {
|
||||
text-decoration: underline;
|
||||
color: #31708f;
|
||||
}
|
||||
|
||||
a:active.tutorial-link {
|
||||
text-decoration: none;
|
||||
color: #31708f;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
|
||||
/* Load Environment Variables */
|
||||
let ENVIRONMENT = require('../Environment.js');
|
||||
let ENVIRONMENT_MODULE = ENVIRONMENT.newEnvironment()
|
||||
global.env = ENVIRONMENT_MODULE
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
if (err.message.indexOf("EADDRINUSE") > 0) {
|
||||
console.log("A Superalgos Client cannot be started. Reason: the port " + port + " is already in use by another application.")
|
||||
@@ -113,15 +118,15 @@ try {
|
||||
WEB_SOCKETS_INTERFACE = WEB_SOCKETS_INTERFACE.newWebSocketsInterface(EVENT_SERVER)
|
||||
WEB_SOCKETS_INTERFACE.initialize()
|
||||
WEB_SOCKETS_INTERFACE.run()
|
||||
console.log('Web Sockets Interface .............. Listening at port ' + process.env.WEB_SOCKETS_INTERFACE_PORT)
|
||||
console.log('Web Sockets Interface .............. Listening at port ' + global.env.WEB_SOCKETS_INTERFACE_PORT)
|
||||
|
||||
HTTP_INTERFACE = HTTP_INTERFACE.newHttpInterface(WEB_SERVER, DATA_FILE_SERVER, PROJECT_FILE_SERVER, UI_FILE_SERVER, PLUGIN_SERVER, CCXT_SERVER, WEB3_SERVER)
|
||||
HTTP_INTERFACE.initialize()
|
||||
HTTP_INTERFACE.run()
|
||||
console.log('Http Interface ..................... Listening at port ' + process.env.HTTP_INTERFACE_PORT)
|
||||
console.log('Http Interface ..................... Listening at port ' + global.env.HTTP_INTERFACE_PORT)
|
||||
|
||||
console.log('')
|
||||
console.log("You are running Superalgos Beta 7")
|
||||
console.log("You are running Superalgos Beta 7 SP 1")
|
||||
console.log('')
|
||||
console.log("What's new? The following was implemented here:")
|
||||
console.log('')
|
||||
|
||||
@@ -6,14 +6,9 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
run: run
|
||||
}
|
||||
|
||||
require('dotenv').config()
|
||||
const open = require('open')
|
||||
|
||||
CONSOLE_LOG = process.env.CONSOLE_LOG === 'true'
|
||||
CONSOLE_ERROR_LOG = process.env.CONSOLE_ERROR_LOG === 'true'
|
||||
LOG_FILE_CONTENT = process.env.LOG_FILE_CONTENT === 'true'
|
||||
|
||||
let port = process.env.HTTP_INTERFACE_PORT
|
||||
let port = global.env.HTTP_INTERFACE_PORT
|
||||
|
||||
let http = require('http')
|
||||
let isHttpServerStarted = false
|
||||
@@ -35,7 +30,6 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
|
||||
function startHtttpServer() {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] httpInterface -> startHtttpServer -> Entering function.') }
|
||||
|
||||
try {
|
||||
if (isHttpServerStarted === false) {
|
||||
@@ -55,7 +49,6 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
|
||||
function onBrowserRequest(httpRequest, httpResponse) {
|
||||
if (CONSOLE_LOG === true && httpRequest.url.indexOf('NO-LOG') === -1) { console.log('[INFO] httpInterface -> onBrowserRequest -> httpRequest.url = ' + httpRequest.url) }
|
||||
|
||||
function getBody(callback) { // Gets the de body from a POST httpRequest to the web server
|
||||
try {
|
||||
@@ -75,11 +68,11 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
})
|
||||
|
||||
httpRequest.on('error', function (err) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] httpInterface -> onBrowserRequest -> getBody -> err = ' + err.stack) }
|
||||
console.log('[INFO] httpInterface -> onBrowserRequest -> getBody -> err = ' + err.stack)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_OK_RESPONSE), httpResponse)
|
||||
})
|
||||
} catch (err) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] httpInterface -> onBrowserRequest -> getBody -> err = ' + err.stack) }
|
||||
console.log('[INFO] httpInterface -> onBrowserRequest -> getBody -> err = ' + err.stack)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_OK_RESPONSE), httpResponse)
|
||||
}
|
||||
}
|
||||
@@ -137,9 +130,9 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] httpInterface -> WEB3s -> Method call produced an error.') }
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] httpInterface -> WEB3s -> err.stack = ' + err.stack) }
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] httpInterface -> WEB3s -> Params Received = ' + body) }
|
||||
console.log('[ERROR] httpInterface -> WEB3s -> Method call produced an error.')
|
||||
console.log('[ERROR] httpInterface -> WEB3s -> err.stack = ' + err.stack)
|
||||
console.log('[ERROR] httpInterface -> WEB3s -> Params Received = ' + body)
|
||||
|
||||
let error = {
|
||||
result: 'Fail Because',
|
||||
@@ -219,7 +212,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
err: global.DEFAULT_FAIL_RESPONSE // method not supported
|
||||
}
|
||||
} catch (err) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] httpInterface -> CCXT FetchMarkets -> Could not fetch markets.') }
|
||||
console.log('[INFO] httpInterface -> CCXT FetchMarkets -> Could not fetch markets.')
|
||||
let error = {
|
||||
result: 'Fail Because',
|
||||
message: err.message
|
||||
@@ -310,19 +303,19 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
|
||||
case 'LegacyPlotter.js':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CLIENT + 'WebServer/LegacyPlotter.js', httpResponse)
|
||||
respondWithFile(global.env.PATH_TO_CLIENT + 'WebServer/LegacyPlotter.js', httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
case 'PlotterPanel.js':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CLIENT + 'WebServer/PlotterPanel.js', httpResponse)
|
||||
respondWithFile(global.env.PATH_TO_CLIENT + 'WebServer/PlotterPanel.js', httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Images': // This means the Images folder.
|
||||
{
|
||||
let path = process.env.PATH_TO_CLIENT + 'WebServer/Images/' + requestParameters[2]
|
||||
let path = global.env.PATH_TO_CLIENT + 'WebServer/Images/' + requestParameters[2]
|
||||
|
||||
if (requestParameters[3] !== undefined) {
|
||||
path = path + '/' + requestParameters[3]
|
||||
@@ -344,7 +337,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
|
||||
case 'Icons': // This means the Icons folder under Projects.
|
||||
{
|
||||
let path = process.env.PROJECTS_PATH + '/' + requestParameters[2] + '/Icons'
|
||||
let path = global.env.PATH_TO_PROJECTS + '/' + requestParameters[2] + '/Icons'
|
||||
|
||||
if (requestParameters[3] !== undefined) {
|
||||
path = path + '/' + requestParameters[3]
|
||||
@@ -365,7 +358,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
|
||||
case 'Gifs': // This means the Gifs folder under Projects.
|
||||
{
|
||||
let path = process.env.PROJECTS_PATH + '/' + requestParameters[2] + '/Gifs'
|
||||
let path = global.env.PATH_TO_PROJECTS + '/' + requestParameters[2] + '/Gifs'
|
||||
|
||||
if (requestParameters[3] !== undefined) {
|
||||
path = path + '/' + requestParameters[3]
|
||||
@@ -386,19 +379,19 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
|
||||
case 'favicon.ico': // This means the Scripts folder.
|
||||
{
|
||||
respondWithImage(process.env.PATH_TO_CLIENT + 'WebServer/Images/' + 'favicon.ico', httpResponse)
|
||||
respondWithImage(global.env.PATH_TO_CLIENT + 'WebServer/Images/' + 'favicon.ico', httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
case 'WebServer': // This means the WebServer folder.
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CLIENT + 'WebServer/' + requestParameters[2], httpResponse)
|
||||
respondWithFile(global.env.PATH_TO_CLIENT + 'WebServer/' + requestParameters[2], httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
case 'externalScripts': // This means the WebServer folder.
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CLIENT + 'WebServer/externalScripts/' + requestParameters[2], httpResponse)
|
||||
respondWithFile(global.env.PATH_TO_CLIENT + 'WebServer/externalScripts/' + requestParameters[2], httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
@@ -408,45 +401,45 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
let dataMine = requestParameters[3]
|
||||
let codeName = requestParameters[4]
|
||||
let moduleName = requestParameters[5]
|
||||
let filePath = process.env.PROJECTS_PATH + '/' + project + '/' + 'Bots-Plotters-Code' + '/' + dataMine + '/plotters/' + codeName + '/' + moduleName
|
||||
let filePath = global.env.PATH_TO_PROJECTS + '/' + project + '/' + 'Bots-Plotters-Code' + '/' + dataMine + '/plotters/' + codeName + '/' + moduleName
|
||||
respondWithFile(filePath, httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
case 'ChartLayers':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_UI + '/' + requestParameters[1] + '/' + requestParameters[2], httpResponse)
|
||||
respondWithFile(global.env.PATH_TO_UI + '/' + requestParameters[1] + '/' + requestParameters[2], httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Files':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_DATA_FILES + '/' + requestParameters[2], httpResponse)
|
||||
respondWithFile(global.env.PATH_TO_DATA_FILES + '/' + requestParameters[2], httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Fonts':
|
||||
{
|
||||
respondWithFont(process.env.PATH_TO_FONTS + '/' + requestParameters[2], httpResponse)
|
||||
respondWithFont(global.env.PATH_TO_FONTS + '/' + requestParameters[2], httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
case 'ProjectNames':
|
||||
{
|
||||
let projects = getDirectories(process.env.PROJECTS_PATH)
|
||||
let projects = getDirectories(global.env.PATH_TO_PROJECTS)
|
||||
respondWithContent(JSON.stringify(projects), httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Schema':
|
||||
{
|
||||
sendSchema(process.env.PROJECTS_PATH + '/' + requestParameters[2] + '/Schemas/', requestParameters[3] + '.json')
|
||||
sendSchema(global.env.PATH_TO_PROJECTS + '/' + requestParameters[2] + '/Schemas/', requestParameters[3] + '.json')
|
||||
}
|
||||
break
|
||||
|
||||
case 'IconNames':
|
||||
{
|
||||
let projects = getDirectories(process.env.PROJECTS_PATH)
|
||||
let projects = getDirectories(global.env.PATH_TO_PROJECTS)
|
||||
const fs = require('fs')
|
||||
|
||||
let icons = []
|
||||
@@ -456,7 +449,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
let project = projects[i]
|
||||
|
||||
const folder = process.env.PROJECTS_PATH + '/' + project + '/Icons/'
|
||||
const folder = global.env.PATH_TO_PROJECTS + '/' + project + '/Icons/'
|
||||
|
||||
fs.readdir(folder, (err, files) => {
|
||||
for (let j = 0; j < files.length; j++) {
|
||||
@@ -479,7 +472,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
let pluginType = unescape(requestParameters[3])
|
||||
|
||||
const fs = require('fs')
|
||||
let folder = process.env.PROJECTS_PATH + '/' + project + '/Plugins/' + pluginType
|
||||
let folder = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/' + pluginType
|
||||
|
||||
fs.readdir(folder, (err, files) => {
|
||||
respondWithContent(JSON.stringify(files), httpResponse)
|
||||
@@ -492,7 +485,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
let project = unescape(requestParameters[2])
|
||||
let pluginType = unescape(requestParameters[3])
|
||||
let fileName = unescape(requestParameters[4])
|
||||
let filePath = process.env.PROJECTS_PATH + '/' + project + '/Plugins/' + pluginType + '/' + fileName
|
||||
let filePath = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/' + pluginType + '/' + fileName
|
||||
respondWithFile(filePath, httpResponse)
|
||||
}
|
||||
break
|
||||
@@ -502,7 +495,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
let fs = require('fs')
|
||||
|
||||
try {
|
||||
let filePath = process.env.DEFAULT_WORKSPACE_PATH + '/Getting-Started.json'
|
||||
let filePath = global.env.PATH_TO_DEFAULT_WORKSPACE + '/Getting-Started.json'
|
||||
fs.readFile(filePath, onFileRead)
|
||||
} catch (e) {
|
||||
console.log('[ERROR] Error reading the Workspace.', e)
|
||||
@@ -522,21 +515,21 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
case 'ListWorkspaces':
|
||||
{
|
||||
let allWorkspaces = []
|
||||
let projects = getDirectories(process.env.PROJECTS_PATH)
|
||||
let projects = getDirectories(global.env.PATH_TO_PROJECTS)
|
||||
let projectsCount = 0
|
||||
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
let project = projects[i]
|
||||
readPluginWorkspaces()
|
||||
function readPluginWorkspaces() {
|
||||
let dirPath = process.env.PROJECTS_PATH + '/' + project + '/Plugins/Workspaces'
|
||||
let dirPath = global.env.PATH_TO_PROJECTS + '/' + project + '/Plugins/Workspaces'
|
||||
try {
|
||||
let fs = require('fs')
|
||||
fs.readdir(dirPath, onDirRead)
|
||||
|
||||
function onDirRead(err, fileList) {
|
||||
if (err) {
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[WARN] Error reading a directory content. filePath = ' + dirPath) }
|
||||
console.log('[WARN] Error reading a directory content. filePath = ' + dirPath)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), httpResponse)
|
||||
return
|
||||
} else {
|
||||
@@ -554,8 +547,8 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath) }
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] err.stack = ' + err.stack) }
|
||||
console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath)
|
||||
console.log('[ERROR] err.stack = ' + err.stack)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), httpResponse)
|
||||
return
|
||||
}
|
||||
@@ -563,14 +556,14 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
|
||||
function readMyWorkspaces() {
|
||||
let dirPath = process.env.MY_WORKSPACES_PATH
|
||||
let dirPath = global.env.PATH_TO_MY_WORKSPACES
|
||||
try {
|
||||
let fs = require('fs')
|
||||
fs.readdir(dirPath, onDirRead)
|
||||
|
||||
function onDirRead(err, fileList) {
|
||||
if (err) {
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[WARN] Error reading a directory content. filePath = ' + dirPath) }
|
||||
console.log('[WARN] Could not read this directory content. filePath = ' + dirPath)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), httpResponse)
|
||||
return
|
||||
} else {
|
||||
@@ -585,8 +578,8 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath) }
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] err.stack = ' + err.stack) }
|
||||
console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath)
|
||||
console.log('[ERROR] err.stack = ' + err.stack)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), httpResponse)
|
||||
return
|
||||
}
|
||||
@@ -597,7 +590,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
case 'LoadMyWorkspace':
|
||||
{
|
||||
let fileName = unescape(requestParameters[2])
|
||||
let filePath = process.env.MY_WORKSPACES_PATH + '/' + fileName + '.json'
|
||||
let filePath = global.env.PATH_TO_MY_WORKSPACES + '/' + fileName + '.json'
|
||||
respondWithFile(filePath, httpResponse)
|
||||
}
|
||||
break
|
||||
@@ -610,11 +603,11 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
|
||||
let fileContent = body
|
||||
let fileName = unescape(requestParameters[2])
|
||||
let filePath = process.env.MY_WORKSPACES_PATH + '/' + fileName + '.json'
|
||||
let filePath = global.env.PATH_TO_MY_WORKSPACES + '/' + fileName + '.json'
|
||||
|
||||
try {
|
||||
let fs = require('fs')
|
||||
let dir = process.env.MY_WORKSPACES_PATH;
|
||||
let dir = global.env.PATH_TO_MY_WORKSPACES;
|
||||
|
||||
/* Create Dir if it does not exist */
|
||||
if (!fs.existsSync(dir)) {
|
||||
@@ -660,7 +653,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
|
||||
case 'ProjectsSchema':
|
||||
{
|
||||
let path = process.env.PROJECTS_PATH + '/' + 'ProjectsSchema.json'
|
||||
let path = global.env.PATH_TO_PROJECTS + '/' + 'ProjectsSchema.json'
|
||||
respondWithFile(path, httpResponse)
|
||||
}
|
||||
break
|
||||
@@ -669,15 +662,15 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
{
|
||||
let fs = require('fs')
|
||||
let allFiles = []
|
||||
let projects = getDirectories(process.env.PROJECTS_PATH)
|
||||
let projects = getDirectories(global.env.PATH_TO_PROJECTS)
|
||||
let dirCount = 0
|
||||
let totalDirs = 0
|
||||
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
let project = projects[i]
|
||||
|
||||
let dirPath = project + '/Spaces'
|
||||
let spaces = getDirectories(process.env.PROJECTS_PATH + '/' + dirPath)
|
||||
let dirPath = project + '/UI/Spaces'
|
||||
let spaces = getDirectories(global.env.PATH_TO_PROJECTS + '/' + dirPath)
|
||||
|
||||
for (let j = 0; j < spaces.length; j++) {
|
||||
let space = spaces[j]
|
||||
@@ -688,9 +681,9 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
try {
|
||||
|
||||
totalDirs++
|
||||
fs.readdir(process.env.PROJECTS_PATH + '/' + path, onDirRead)
|
||||
fs.readdir(global.env.PATH_TO_PROJECTS + '/' + path, onDirRead)
|
||||
|
||||
let otherDirs = getDirectories(process.env.PROJECTS_PATH + '/' + path)
|
||||
let otherDirs = getDirectories(global.env.PATH_TO_PROJECTS + '/' + path)
|
||||
for (let m = 0; m < otherDirs.length; m++) {
|
||||
let otherDir = otherDirs[m]
|
||||
readDirectory(path + '/' + otherDir)
|
||||
@@ -715,9 +708,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('[ERROR] Error reading a directory content. filePath = ' + path)
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] err.stack = ' + err.stack) }
|
||||
|
||||
console.log(err.stack)
|
||||
console.log('[ERROR] err.stack = ' + err.stack)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), httpResponse)
|
||||
return
|
||||
}
|
||||
@@ -748,14 +739,14 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
|
||||
}
|
||||
let filePath = process.env.PROJECTS_PATH + path
|
||||
let filePath = global.env.PATH_TO_PROJECTS + path
|
||||
respondWithFile(filePath, httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Storage':
|
||||
{
|
||||
respondWithFile(process.env.STORAGE_PATH + '/' + httpRequest.url.substring(9), httpResponse)
|
||||
respondWithFile(global.env.PATH_TO_DATA_STORAGE + '/' + httpRequest.url.substring(9), httpResponse)
|
||||
}
|
||||
break
|
||||
|
||||
@@ -785,21 +776,20 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
function returnProjectFolderFileList(projectFolderName) {
|
||||
{
|
||||
let allLibraries = []
|
||||
let projects = getDirectories(process.env.PROJECTS_PATH)
|
||||
let projects = getDirectories(global.env.PATH_TO_PROJECTS)
|
||||
let projectsCount = 0
|
||||
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
let project = projects[i]
|
||||
|
||||
let dirPath = process.env.PROJECTS_PATH + '/' + project + '/' + projectFolderName
|
||||
let dirPath = global.env.PATH_TO_PROJECTS + '/' + project + '/' + 'UI' + '/' + projectFolderName
|
||||
try {
|
||||
let fs = require('fs')
|
||||
fs.readdir(dirPath, onDirRead)
|
||||
|
||||
function onDirRead(err, fileList) {
|
||||
if (err) {
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[WARN] Error reading a directory content. filePath = ' + dirPath) }
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log(err.stack) }
|
||||
console.log('[WARN] Error reading a directory content. filePath = ' + dirPath)
|
||||
return
|
||||
} else {
|
||||
let updatedFileList = []
|
||||
@@ -816,8 +806,8 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath) }
|
||||
if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] err.stack = ' + err.stack) }
|
||||
console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath)
|
||||
console.log('[ERROR] err.stack = ' + err.stack)
|
||||
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), httpResponse)
|
||||
return
|
||||
@@ -863,16 +853,16 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
function sendStyleSheet(fileName) {
|
||||
let fs = require('fs')
|
||||
try {
|
||||
let filePath = process.env.PATH_TO_CLIENT + 'WebServer/' + fileName
|
||||
let filePath = global.env.PATH_TO_CLIENT + 'WebServer/' + fileName
|
||||
fs.readFile(filePath, onFileRead)
|
||||
|
||||
function onFileRead(err, file) {
|
||||
try {
|
||||
let fileContent = file.toString()
|
||||
|
||||
fileContent = fileContent.replace('HTTP_INTERFACE_PORT', process.env.HTTP_INTERFACE_PORT)
|
||||
fileContent = fileContent.replace('HTTP_INTERFACE_PORT', process.env.HTTP_INTERFACE_PORT)
|
||||
fileContent = fileContent.replace('HTTP_INTERFACE_PORT', process.env.HTTP_INTERFACE_PORT)
|
||||
fileContent = fileContent.replace('HTTP_INTERFACE_PORT', global.env.HTTP_INTERFACE_PORT)
|
||||
fileContent = fileContent.replace('HTTP_INTERFACE_PORT', global.env.HTTP_INTERFACE_PORT)
|
||||
fileContent = fileContent.replace('HTTP_INTERFACE_PORT', global.env.HTTP_INTERFACE_PORT)
|
||||
respondWithContent(fileContent, httpResponse, 'text/css')
|
||||
} catch (err) {
|
||||
console.log('[ERROR] httpInterface -> mainCSS -> File Not Found: ' + fileName + ' or Error = ' + err.stack)
|
||||
@@ -887,14 +877,14 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
if (requestParameters[1] === '') {
|
||||
let fs = require('fs')
|
||||
try {
|
||||
let fileName = process.env.PATH_TO_CLIENT + 'WebServer/index.html'
|
||||
let fileName = global.env.PATH_TO_CLIENT + 'WebServer/index.html'
|
||||
fs.readFile(fileName, onFileRead)
|
||||
|
||||
function onFileRead(err, file) {
|
||||
try {
|
||||
let fileContent = file.toString()
|
||||
|
||||
fileContent = fileContent.replace('HTTP_INTERFACE_PORT', process.env.HTTP_INTERFACE_PORT)
|
||||
fileContent = fileContent.replace('HTTP_INTERFACE_PORT', global.env.HTTP_INTERFACE_PORT)
|
||||
respondWithContent(fileContent, httpResponse)
|
||||
} catch (err) {
|
||||
console.log('[ERROR] httpInterface -> homePage -> File Not Found: ' + fileName + ' or Error = ' + err.stack)
|
||||
@@ -904,7 +894,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
console.log(err)
|
||||
}
|
||||
} else {
|
||||
respondWithFile(process.env.PATH_TO_UI + '/' + requestParameters[1], httpResponse)
|
||||
respondWithFile(global.env.PATH_TO_UI + '/' + requestParameters[1], httpResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -919,7 +909,6 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
fs.readFile(fileName, onFileRead)
|
||||
|
||||
function onFileRead(err, file) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] httpInterface -> respondWithFile -> onFileRead -> Entering function.') }
|
||||
if (!err) {
|
||||
respondWithContent(file.toString(), httpResponse)
|
||||
} else {
|
||||
@@ -934,8 +923,6 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
|
||||
function respondWithContent(content, httpResponse, contentType) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] httpInterface -> respondWithContent -> Entering function.') }
|
||||
|
||||
try {
|
||||
httpResponse.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate') // HTTP 1.1.
|
||||
httpResponse.setHeader('Pragma', 'no-cache') // HTTP 1.0.
|
||||
@@ -960,8 +947,6 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
|
||||
function respondWithImage(fileName, httpResponse) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] httpInterface -> respondWithImage -> Entering function.') }
|
||||
|
||||
let fs = require('fs')
|
||||
try {
|
||||
fs.readFile(fileName, onFileRead)
|
||||
@@ -989,15 +974,11 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
}
|
||||
|
||||
function respondWithFont(fileName, httpResponse) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] httpInterface -> respondWithBinary -> Entering function.') }
|
||||
|
||||
let fs = require('fs')
|
||||
try {
|
||||
fs.readFile(fileName, onFileRead)
|
||||
|
||||
function onFileRead(err, file) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] httpInterface -> respondWithBinary -> onFileRead -> Entering function.') }
|
||||
|
||||
try {
|
||||
if (err) {
|
||||
console.log('[ERROR] httpInterface -> respondWithBinary -> onFileRead -> File Not Found: ' + fileName + ' or Error = ' + err.stack)
|
||||
@@ -1025,7 +1006,6 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE
|
||||
|
||||
function returnEmptyArray(httpResponse) {
|
||||
try {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] httpInterface -> returnEmptyArray -> Entering function.') }
|
||||
httpResponse.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate') // HTTP 1.1.
|
||||
httpResponse.setHeader('Pragma', 'no-cache') // HTTP 1.0.
|
||||
httpResponse.setHeader('Expires', '0') // Proxies.
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
(function () {
|
||||
require('./lib/main').config(
|
||||
Object.assign(
|
||||
{},
|
||||
require('./lib/env-options'),
|
||||
require('./lib/cli-options')(process.argv)
|
||||
)
|
||||
)
|
||||
})()
|
||||
@@ -1,13 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
const re = /^dotenv_config_(encoding|path|debug)=(.+)$/
|
||||
|
||||
module.exports = function optionMatcher (args /*: Array<string> */) {
|
||||
return args.reduce(function (acc, cur) {
|
||||
const matches = cur.match(re)
|
||||
if (matches) {
|
||||
acc[matches[1]] = matches[2]
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
// ../config.js accepts options via environment variables
|
||||
const options = {}
|
||||
|
||||
if (process.env.DOTENV_CONFIG_ENCODING != null) {
|
||||
options.encoding = process.env.DOTENV_CONFIG_ENCODING
|
||||
}
|
||||
|
||||
if (process.env.DOTENV_CONFIG_PATH != null) {
|
||||
options.path = process.env.DOTENV_CONFIG_PATH
|
||||
}
|
||||
|
||||
if (process.env.DOTENV_CONFIG_DEBUG != null) {
|
||||
options.debug = process.env.DOTENV_CONFIG_DEBUG
|
||||
}
|
||||
|
||||
module.exports = options
|
||||
@@ -1,113 +0,0 @@
|
||||
/* @flow */
|
||||
/*::
|
||||
|
||||
type DotenvParseOptions = {
|
||||
debug?: boolean
|
||||
}
|
||||
|
||||
// keys and values from src
|
||||
type DotenvParseOutput = { [string]: string }
|
||||
|
||||
type DotenvConfigOptions = {
|
||||
path?: string, // path to .env file
|
||||
encoding?: string, // encoding of .env file
|
||||
debug?: string // turn on logging for debugging purposes
|
||||
}
|
||||
|
||||
type DotenvConfigOutput = {
|
||||
parsed?: DotenvParseOutput,
|
||||
error?: Error
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
function log (message /*: string */) {
|
||||
console.log(`[dotenv][DEBUG] ${message}`)
|
||||
}
|
||||
|
||||
const NEWLINE = '\n'
|
||||
const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/
|
||||
const RE_NEWLINES = /\\n/g
|
||||
const NEWLINES_MATCH = /\n|\r|\r\n/
|
||||
|
||||
// Parses src into an Object
|
||||
function parse (src /*: string | Buffer */, options /*: ?DotenvParseOptions */) /*: DotenvParseOutput */ {
|
||||
const debug = Boolean(options && options.debug)
|
||||
const obj = {}
|
||||
|
||||
// convert Buffers before splitting into lines and processing
|
||||
src.toString().split(NEWLINES_MATCH).forEach(function (line, idx) {
|
||||
// matching "KEY' and 'VAL' in 'KEY=VAL'
|
||||
const keyValueArr = line.match(RE_INI_KEY_VAL)
|
||||
// matched?
|
||||
if (keyValueArr != null) {
|
||||
const key = keyValueArr[1]
|
||||
// default undefined or missing values to empty string
|
||||
let val = (keyValueArr[2] || '')
|
||||
const end = val.length - 1
|
||||
const isDoubleQuoted = val[0] === '"' && val[end] === '"'
|
||||
const isSingleQuoted = val[0] === "'" && val[end] === "'"
|
||||
|
||||
// if single or double quoted, remove quotes
|
||||
if (isSingleQuoted || isDoubleQuoted) {
|
||||
val = val.substring(1, end)
|
||||
|
||||
// if double quoted, expand newlines
|
||||
if (isDoubleQuoted) {
|
||||
val = val.replace(RE_NEWLINES, NEWLINE)
|
||||
}
|
||||
} else {
|
||||
// remove surrounding whitespace
|
||||
val = val.trim()
|
||||
}
|
||||
|
||||
obj[key] = val
|
||||
} else if (debug) {
|
||||
log(`did not match key and value when parsing line ${idx + 1}: ${line}`)
|
||||
}
|
||||
})
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
// Populates process.env from .env file
|
||||
function config (options /*: ?DotenvConfigOptions */) /*: DotenvConfigOutput */ {
|
||||
let dotenvPath = path.resolve(process.cwd(), '.env')
|
||||
let encoding /*: string */ = 'utf8'
|
||||
let debug = false
|
||||
|
||||
if (options) {
|
||||
if (options.path != null) {
|
||||
dotenvPath = options.path
|
||||
}
|
||||
if (options.encoding != null) {
|
||||
encoding = options.encoding
|
||||
}
|
||||
if (options.debug != null) {
|
||||
debug = true
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// specifying an encoding returns a string instead of a buffer
|
||||
const parsed = parse(fs.readFileSync(dotenvPath, { encoding }), { debug })
|
||||
|
||||
Object.keys(parsed).forEach(function (key) {
|
||||
if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
|
||||
process.env[key] = parsed[key]
|
||||
} else if (debug) {
|
||||
log(`"${key}" is already defined in \`process.env\` and will not be overwritten`)
|
||||
}
|
||||
})
|
||||
|
||||
return { parsed }
|
||||
} catch (e) {
|
||||
return { error: e }
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.config = config
|
||||
module.exports.parse = parse
|
||||
@@ -1,79 +0,0 @@
|
||||
{
|
||||
"_from": "dotenv@^8.2.0",
|
||||
"_id": "dotenv@8.2.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
|
||||
"_location": "/dotenv",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "range",
|
||||
"registry": true,
|
||||
"raw": "dotenv@^8.2.0",
|
||||
"name": "dotenv",
|
||||
"escapedName": "dotenv",
|
||||
"rawSpec": "^8.2.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "^8.2.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||
"_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a",
|
||||
"_spec": "dotenv@^8.2.0",
|
||||
"_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\BackendServers",
|
||||
"bugs": {
|
||||
"url": "https://github.com/motdotla/dotenv/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {},
|
||||
"deprecated": false,
|
||||
"description": "Loads environment variables from .env file",
|
||||
"devDependencies": {
|
||||
"decache": "^4.5.1",
|
||||
"dtslint": "^0.9.8",
|
||||
"flow-bin": "^0.109.0",
|
||||
"sinon": "^7.5.0",
|
||||
"standard": "^13.1.0",
|
||||
"standard-markdown": "^5.1.0",
|
||||
"standard-version": "^7.0.0",
|
||||
"tap": "^14.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"homepage": "https://github.com/motdotla/dotenv#readme",
|
||||
"keywords": [
|
||||
"dotenv",
|
||||
"env",
|
||||
".env",
|
||||
"environment",
|
||||
"variables",
|
||||
"config",
|
||||
"settings"
|
||||
],
|
||||
"license": "BSD-2-Clause",
|
||||
"main": "lib/main.js",
|
||||
"name": "dotenv",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/motdotla/dotenv.git"
|
||||
},
|
||||
"scripts": {
|
||||
"dtslint": "dtslint types",
|
||||
"flow": "flow",
|
||||
"lint": "standard",
|
||||
"postlint": "standard-markdown",
|
||||
"prerelease": "npm test",
|
||||
"pretest": "npm run lint && npm run dtslint",
|
||||
"release": "standard-version",
|
||||
"test": "tap tests/*.js --100"
|
||||
},
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"flow-typed/"
|
||||
]
|
||||
},
|
||||
"types": "types",
|
||||
"version": "8.2.0"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": ["es6"],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noEmit": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"dotenv": ["."]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "dtslint/dtslint.json",
|
||||
"rules": {
|
||||
"strict-export-declare-modifiers": false
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "client",
|
||||
"name": "Client",
|
||||
"version": "0.0.6",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
@@ -812,11 +812,6 @@
|
||||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
|
||||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
|
||||
},
|
||||
"duplexer3": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
{
|
||||
"name": "client",
|
||||
"name": "Client",
|
||||
"version": "0.0.6",
|
||||
"description": "BackendServer",
|
||||
"main": "server.js",
|
||||
"main": "client.js",
|
||||
"author": {
|
||||
"name": "Luis-Fernando-Molina"
|
||||
},
|
||||
"dependencies": {
|
||||
"ccxt": "^1.23.67",
|
||||
"child_process": "^1.0.2",
|
||||
"dotenv": "^8.2.0",
|
||||
"open": "^6.4.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"web3": "^1.3.0",
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
*/
|
||||
|
||||
const { fork } = require('child_process')
|
||||
require('dotenv').config()
|
||||
tasksMap = new Map()
|
||||
|
||||
return thisObject
|
||||
@@ -64,7 +63,7 @@
|
||||
//console.log('[INFO] Client -> Task Manager Server -> runTask -> Task Name = ' + message.event.taskName)
|
||||
//console.log('[INFO] Client -> Task Manager Server -> runTask -> Task Id = ' + message.event.taskId)
|
||||
|
||||
let path = process.env.TASK_SERVER_PATH + '/server.js'
|
||||
let path = global.env.PATH_TO_TASK_SERVER + '/Task.js'
|
||||
|
||||
/* Workarround to avoid having the same debug port at the forked process which makes it crash. */
|
||||
for (let i = 0; i < process.execArgv.length; i++) {
|
||||
|
||||
@@ -9,10 +9,9 @@
|
||||
run: run
|
||||
}
|
||||
|
||||
require('dotenv').config()
|
||||
const WEB_SOCKET = require('ws')
|
||||
let socketServer
|
||||
let port = process.env.WEB_SOCKETS_INTERFACE_PORT
|
||||
let port = global.env.WEB_SOCKETS_INTERFACE_PORT
|
||||
|
||||
return thisObject
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
exports.newEnvironment = function () {
|
||||
|
||||
let thisObject = {
|
||||
WEB_SERVER_URL: 'localhost',
|
||||
WEB_SOCKETS_INTERFACE_PORT: 18041,
|
||||
HTTP_INTERFACE_PORT: 34248,
|
||||
PATH_TO_TASK_SERVER: './TaskServer',
|
||||
PATH_TO_DATA_STORAGE: './Data-Storage',
|
||||
PATH_TO_PROJECTS: './Projects',
|
||||
PATH_TO_LOG_FILES: './Log-Files',
|
||||
PATH_TO_PROJECTS_REQUIRED: '../Projects',
|
||||
PATH_TO_UI: './UI',
|
||||
PATH_TO_DATA_FILES: './UI/Data-Files/src',
|
||||
PATH_TO_CLIENT: './Client/',
|
||||
PATH_TO_DEFAULT_WORKSPACE: './Projects/Superalgos/Plugins/Workspaces',
|
||||
PATH_TO_MY_WORKSPACES: './My-Workspaces',
|
||||
PATH_TO_FONTS: './Client/WebServer/Fonts'
|
||||
}
|
||||
|
||||
return thisObject
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{"type":"Workspace","name":"Ethereum Integration Demo","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataMining":{"type":"Data Mining","name":"New Data Mining","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Masters","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Masters","project":"Superalgos","tasks":[{"type":"Task","name":"Exchange Raw Data","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Exchange Raw Data","config":"{ \n\"startDate\": \"2017-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Exchange Raw Data Historic-OHLCVs","project":"Superalgos","id":"da7e6d2a-76d5-431c-ba48-aa98ebd2a907","savedPayload":{"position":{"x":23623.030015561097,"y":29888.16403283887},"targetPosition":{"x":23918.47234146476,"y":29836.06957953879},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Historic-OHLCVs","id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc"}}}],"id":"f9daa393-935e-4a9d-bdc5-706d97ac5530","savedPayload":{"position":{"x":23918.47234146476,"y":29836.06957953879},"targetPosition":{"x":24213.914667368423,"y":29783.97512623871},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"5827edbc-89f8-495a-953a-a568f2fca44e","savedPayload":{"position":{"x":24213.914667368423,"y":29783.97512623871},"targetPosition":{"x":24509.356993272086,"y":29731.88067293863},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Candles Volumes","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Candles Volumes","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"243ecbf4-cb69-42e2-9acb-b03c7c481b79","savedPayload":{"position":{"x":23619.613932037235,"y":29653.83848916277},"targetPosition":{"x":23918.47234146476,"y":29627.69176633847},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"9f683143-a33f-42c1-9fa8-c601f01ee4e1"}}},{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Daily","project":"Superalgos","id":"c90cb0e5-3e49-40ba-b919-38b0e5f7fcee","savedPayload":{"position":{"x":23646.580005353764,"y":29500.906287816262},"targetPosition":{"x":23918.47234146476,"y":29627.69176633847},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"980ceb1d-7be6-454f-90d9-01ba1fd4a65d"}}}],"id":"ac31f04b-4d79-4e18-9262-1a9a933b6156","savedPayload":{"position":{"x":23918.47234146476,"y":29627.69176633847},"targetPosition":{"x":24213.914667368423,"y":29679.78621963855},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"46c3f665-a9e2-46dc-b569-2a928d2067af","savedPayload":{"position":{"x":24213.914667368423,"y":29679.78621963855},"targetPosition":{"x":24509.356993272086,"y":29731.88067293863},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Bollinger Bands","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Bollinger Bands","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Bollinger Bands Multi-Period-Market","project":"Superalgos","id":"12498614-646b-411c-9c82-747bacb8d7a6","savedPayload":{"position":{"x":23699.9640031147,"y":29354.234959407873},"targetPosition":{"x":23989.74175100142,"y":29431.88067293863},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"941a0543-0cc0-4a5d-a782-728d2835c100"}}},{"typeLine truncated
|
||||
{"type":"Workspace","name":"Ethereum Integration Demo","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataTasks":{"type":"Data Tasks","name":"New Data Tasks","project":"Superalgos","projectDataTasks":[{"type":"Project Data Tasks","name":"New Project Definition","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Masters","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Masters","project":"Superalgos","tasks":[{"type":"Task","name":"Exchange Raw Data","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Exchange Raw Data","config":"{ \n\"startDate\": \"2020-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Exchange Raw Data Historic-OHLCVs","project":"Superalgos","id":"790c56a4-deba-499f-9756-115fdb8cab44","savedPayload":{"position":{"x":25276.356993272086,"y":30604.11115747996},"targetPosition":{"x":25218.356993272086,"y":30630.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Historic-OHLCVs","id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc"}}}],"id":"8a5bbe7c-4a5c-4c4a-ad2b-38cf489c859a","savedPayload":{"position":{"x":25218.356993272086,"y":30630.11115747996},"targetPosition":{"x":25145.356993272086,"y":30724.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"56ceaef5-290c-4512-94c9-2f5fd13486d1","savedPayload":{"position":{"x":25145.356993272086,"y":30724.11115747996},"targetPosition":{"x":25092.356993272086,"y":30693.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Webhooks","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Webhooks","config":"{ \n\"startDate\": \"2020-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Webhooks Check-Webhook","project":"Superalgos","id":"0a8d8265-e0f8-4f3a-96d0-bfe4bbbd3224","savedPayload":{"position":{"x":25136.356993272086,"y":30684.11115747996},"targetPosition":{"x":25152.356993272086,"y":30784.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Check-Webhook","id":"69f37820-ab16-4e19-bfd8-386dd6e249a3"}}}],"id":"718a49a9-deae-4849-a796-714feb1e08bc","savedPayload":{"position":{"x":25152.356993272086,"y":30784.11115747996},"targetPosition":{"x":25081.356993272086,"y":30703.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"31747cdc-3783-40be-860f-92e381003ffe","savedPayload":{"position":{"x":25081.356993272086,"y":30703.11115747996},"targetPosition":{"x":25092.356993272086,"y":30693.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Candles Volumes","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Candles Volumes","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"1daa3ec2-c891-44ab-997a-f427a8586716","savedPayload":{"position":{"x":25041.356993272086,"y":30670.11115747996},"targetPosition":{"x":25039.356993272086,"y":30732.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"9f683143-a33f-42c1-9fa8-c601f01ee4e1"}}},{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Daily","project":"Superalgos","id":"8225345d-7cd7-4889-99b0-af692402d269","savedPayload":{"position":{"x":24989.356993272086,"y":30689.11115747996},"targetPosition":{"x":25039.356993272086,"y":30732.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":Line truncated
|
||||
@@ -26,6 +26,12 @@
|
||||
"relatedUiObject": "Ethereum Wallet",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Data Mine",
|
||||
"relatedUiObject": "Data Mine",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
@@ -41,7 +47,16 @@
|
||||
"addLeftIcons": true,
|
||||
"isPinned": true,
|
||||
"positionLocked": true,
|
||||
"icon": "ethereum"
|
||||
"icon": "ethereum",
|
||||
"properties": [
|
||||
{
|
||||
"name": "projectDefinition",
|
||||
"type": "node",
|
||||
"childType": "Project Definition",
|
||||
"project": "Superalgos",
|
||||
"autoAdd": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Ethereum Wallet",
|
||||
@@ -200,7 +215,7 @@
|
||||
"propertyNameAtParent": "ethBalance",
|
||||
"icon": "ethereum"
|
||||
},
|
||||
{
|
||||
{
|
||||
"type": "Token Balance",
|
||||
"menuItems": [
|
||||
{
|
||||
@@ -686,5 +701,318 @@
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"icon": "ethereum"
|
||||
},
|
||||
{
|
||||
"type": "Project Data Tasks",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Data Tasks->"
|
||||
},
|
||||
"propertyNameAtParent": "projectDataTasks",
|
||||
"properties": [],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Project Learning Tasks",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Learning Tasks->"
|
||||
},
|
||||
"propertyNameAtParent": "projectLearningTasks",
|
||||
"properties": [],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Project Trading Tasks",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Trading Tasks->"
|
||||
},
|
||||
"propertyNameAtParent": "projectTradingTasks",
|
||||
"properties": [],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Project Data Products",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Data Mines Data->"
|
||||
},
|
||||
"propertyNameAtParent": "projectDataProducts",
|
||||
"properties": [],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Project Learning Products",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Learning Mine Data->"
|
||||
},
|
||||
"propertyNameAtParent": "projectLearningProducts",
|
||||
"properties": [],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Project Trading Products",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Trading Mine Data->"
|
||||
},
|
||||
"propertyNameAtParent": "projectTradingProducts",
|
||||
"properties": [],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Project Dashboards",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Charting Space->"
|
||||
},
|
||||
"propertyNameAtParent": "projectDashboards",
|
||||
"properties": [],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Data Mine",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Configure",
|
||||
"label": "Configure",
|
||||
"iconPathOn": "configuration",
|
||||
"iconPathOff": "configuration",
|
||||
"dontShowAtFullscreen": true,
|
||||
"actionFunction": "uiObject.configEditor.activate"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Blockchain Scanner Bot",
|
||||
"relatedUiObject": "Blockchain Scanner Bot",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"isTitleAllwaysVisible": true,
|
||||
"isHierarchyHead": true,
|
||||
"addLeftIcons": true,
|
||||
"editors": {
|
||||
"config": true
|
||||
},
|
||||
"level": 0,
|
||||
"initialValues": {
|
||||
"config": "{ \n\"codeName\": \"Type a name with no spaces or dashes\"\n}"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"name": "blockchainScannerBots",
|
||||
"type": "array",
|
||||
"childType": "Blockchain Scanner Bot"
|
||||
}
|
||||
],
|
||||
"icon": "ethereum"
|
||||
},
|
||||
{
|
||||
"type": "Blockchain Scanner Bot",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Configure",
|
||||
"label": "Configure",
|
||||
"iconPathOn": "configuration",
|
||||
"iconPathOff": "configuration",
|
||||
"dontShowAtFullscreen": true,
|
||||
"actionFunction": "uiObject.configEditor.activate"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Process Definition",
|
||||
"relatedUiObject": "Process Definition",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Product Definition",
|
||||
"relatedUiObject": "Product Definition",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"isTitleAllwaysVisible": true,
|
||||
"addLeftIcons": true,
|
||||
"editors": {
|
||||
"config": true
|
||||
},
|
||||
"initialValues": {
|
||||
"config": "{ \n \"codeName\": \"\"\n}"
|
||||
},
|
||||
"level": 1,
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Data Mine->"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"name": "processes",
|
||||
"type": "array",
|
||||
"childType": "Process Definition",
|
||||
"project": "Superalgos",
|
||||
"autoAdd": true
|
||||
},
|
||||
{
|
||||
"name": "products",
|
||||
"type": "array",
|
||||
"childType": "Product Definition",
|
||||
"project": "Superalgos",
|
||||
"autoAdd": true
|
||||
}
|
||||
],
|
||||
"propertyNameAtParent": "blockchainScannerBots",
|
||||
"icon": "ethereum"
|
||||
}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
// Nothing here to run
|
||||
@@ -1,891 +0,0 @@
|
||||
exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_STORAGE) {
|
||||
|
||||
const FULL_LOG = true;
|
||||
const INTENSIVE_LOG = false;
|
||||
const LOG_FILE_CONTENT = false;
|
||||
|
||||
const GMT_SECONDS = ':00.000 GMT+0000';
|
||||
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
|
||||
|
||||
const MODULE_NAME = "User Bot";
|
||||
|
||||
const TRADES_FOLDER_NAME = "Trades";
|
||||
|
||||
const CANDLES_FOLDER_NAME = "Candles";
|
||||
const BOLLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands";
|
||||
const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth";
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
start: start
|
||||
};
|
||||
|
||||
let utilities = UTILITIES.newCloudUtilities(bot, logger);
|
||||
let fileStorage = FILE_STORAGE.newFileStorage(logger);
|
||||
|
||||
let statusDependencies;
|
||||
let beginingOfMarket
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
logger.fileName = MODULE_NAME;
|
||||
logger.initialize();
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
This process is going to do the following:
|
||||
|
||||
Read the candles from Candles Volumes and produce daily files with bollinger bands.
|
||||
|
||||
*/
|
||||
|
||||
function start(callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
|
||||
|
||||
let market = bot.market;
|
||||
|
||||
/* Context Variables */
|
||||
|
||||
let contextVariables = {
|
||||
lastBandFile: undefined, // Datetime of the last file files sucessfully produced by this process.
|
||||
firstTradeFile: undefined, // Datetime of the first trade file in the whole market history.
|
||||
maxBandFile: undefined // Datetime of the last file available to be used as an input of this process.
|
||||
};
|
||||
|
||||
let previousDay; // Holds the date of the previous day relative to the processing date.
|
||||
let processDate; // Holds the processing date.
|
||||
|
||||
getContextVariables();
|
||||
|
||||
function getContextVariables() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Entering function."); }
|
||||
|
||||
let thisReport;
|
||||
let reportKey;
|
||||
let statusReport;
|
||||
|
||||
/* We look first for Exchange Raw Data in order to get when the market starts. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.beginingOfMarket === undefined) {
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet.");
|
||||
|
||||
let customOK = {
|
||||
result: global.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency does not exist."
|
||||
}
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
||||
callBackFunction(customOK);
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.firstTradeFile = new Date(thisReport.beginingOfMarket.year + "-" + thisReport.beginingOfMarket.month + "-" + thisReport.beginingOfMarket.days + " " + thisReport.beginingOfMarket.hours + ":" + thisReport.beginingOfMarket.minutes + GMT_SECONDS);
|
||||
|
||||
/* Second, we get the report from Candles Volumes, to know when the marted ends. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile === undefined) {
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
|
||||
let customOK = {
|
||||
result: global.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency not ready."
|
||||
}
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
||||
callBackFunction(customOK);
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.maxBandFile = new Date(thisReport.lastFile.valueOf());
|
||||
|
||||
/* Finally we get our own Status Report. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Daily"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.");
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile !== undefined) {
|
||||
|
||||
beginingOfMarket = new Date(thisReport.beginingOfMarket);
|
||||
|
||||
if (beginingOfMarket.valueOf() !== contextVariables.firstTradeFile.valueOf()) { // Reset Mechanism for Begining of the Market
|
||||
logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Reset Mechanism for Begining of the Market Activated. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastBandFile = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastBandFile = new Date(contextVariables.lastBandFile.valueOf() + ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
buildBands();
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.lastBandFile = new Date(thisReport.lastFile);
|
||||
|
||||
/*
|
||||
The bands objects needs to be calculated over more than one day in some situations. In order to simplify the calculations we will
|
||||
always load the last 2 days of candles, and run the calculations on that array.
|
||||
|
||||
1. So first we will load the candles file of processDay -1.
|
||||
2. Secondly we will load the candles file of processDay.
|
||||
|
||||
After reading these two files we will add all candles to a unique array.
|
||||
*/
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile !== undefined"); }
|
||||
|
||||
buildBands();
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
In the case when there is no status report, we take the date of the file with the first trades as the begining of the market. Then we will
|
||||
go one day further in time, so that the previous day does fine a file at the begining of the market.
|
||||
*/
|
||||
|
||||
contextVariables.lastBandFile = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastBandFile = new Date(contextVariables.lastBandFile.valueOf() + ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
beginingOfMarket = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile === undefined"); }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> contextVariables.lastBandFile = " + contextVariables.lastBandFile); }
|
||||
|
||||
buildBands();
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.stack);
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ");
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
|
||||
}
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function buildBands() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> Entering function."); }
|
||||
|
||||
let n;
|
||||
processDate = new Date(contextVariables.lastBandFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop.
|
||||
let fromDate = new Date(processDate.valueOf())
|
||||
let lastDate = new Date()
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> processDate = " + processDate); }
|
||||
|
||||
advanceTime();
|
||||
|
||||
function advanceTime() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> advanceTime -> Entering function."); }
|
||||
|
||||
processDate = new Date(processDate.valueOf() + ONE_DAY_IN_MILISECONDS);
|
||||
previousDay = new Date(processDate.valueOf() - ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> advanceTime -> processDate = " + processDate); }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> advanceTime -> previousDay = " + previousDay); }
|
||||
|
||||
/* Validation that we are not going past the head of the market. */
|
||||
|
||||
if (processDate.valueOf() > contextVariables.maxBandFile.valueOf()) {
|
||||
|
||||
const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + ".";
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> advanceTime -> " + logText); }
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString = processDate.getUTCFullYear() + '-' + utilities.pad(processDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(processDate.getUTCDate(), 2);
|
||||
let currentDate = new Date(processDate)
|
||||
let percentage = global.getPercentage(fromDate, currentDate, lastDate)
|
||||
bot.processHeartBeat(currentDateString, percentage)
|
||||
|
||||
if (global.areEqualDates(currentDate, new Date()) === false) {
|
||||
logger.newInternalLoop(bot.codeName, bot.process, currentDate, percentage);
|
||||
}
|
||||
periodsLoop();
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> advanceTime -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function periodsLoop() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> periodsLoop -> Entering function."); }
|
||||
|
||||
/*
|
||||
|
||||
We will iterate through all posible timeFrames.
|
||||
|
||||
*/
|
||||
|
||||
n = 0 // loop Variable representing each possible period as defined at the periods array.
|
||||
|
||||
loopBody();
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function loopBody() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> Entering function."); }
|
||||
|
||||
const timeFrame = global.dailyFilePeriods[n][1];
|
||||
|
||||
let candles = []; // Here we will put all the candles of the 2 files read.
|
||||
|
||||
let previousDayFile;
|
||||
let processDayFile;
|
||||
|
||||
getPreviousDayFile();
|
||||
|
||||
function getPreviousDayFile() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> getPreviousDayFile -> Entering function."); }
|
||||
|
||||
let dateForPath = previousDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
let filePathRoot = 'Project/' + bot.project + "/" + bot.mineType + "/" + bot.dataMine + "/" + "Candles-Volumes" + '/' + bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset
|
||||
let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timeFrame + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onCurrentDayFileReceived);
|
||||
|
||||
function onCurrentDayFileReceived(err, text) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> text = " + text); }
|
||||
|
||||
previousDayFile = JSON.parse(text);
|
||||
getProcessDayFile()
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> market = " + market.baseAsset + '_' + market.quotedAsset);
|
||||
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getPreviousDayFile -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function getProcessDayFile() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> getProcessDayFile -> Entering function."); }
|
||||
|
||||
let dateForPath = processDate.getUTCFullYear() + '/' + utilities.pad(processDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(processDate.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
let filePathRoot = 'Project/' + bot.project + "/" + bot.mineType + "/" + bot.dataMine + "/" + "Candles-Volumes" + '/' + bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset
|
||||
let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timeFrame + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onCurrentDayFileReceived);
|
||||
|
||||
function onCurrentDayFileReceived(err, text) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> text = " + text); }
|
||||
|
||||
processDayFile = JSON.parse(text);
|
||||
buildBands();
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (processDate.valueOf() > contextVariables.maxBandFile.valueOf()) {
|
||||
|
||||
processDayFile = []; // we are past the head of the market, then no worries if this file is non existent.
|
||||
buildBands();
|
||||
|
||||
} else {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> market = " + market.baseAsset + '_' + market.quotedAsset);
|
||||
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getProcessDayFile -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function buildBands() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> buildBands -> Entering function."); }
|
||||
|
||||
addCandlesToSingleArray(previousDayFile);
|
||||
addCandlesToSingleArray(processDayFile);
|
||||
calculateBands();
|
||||
|
||||
function addCandlesToSingleArray(candlesFile) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> buildBands -> addCandlesToSingleArray -> Entering function."); }
|
||||
|
||||
for (let i = 0; i < candlesFile.length; i++) {
|
||||
|
||||
let candle = {
|
||||
open: undefined,
|
||||
close: undefined,
|
||||
min: 10000000000000,
|
||||
max: 0,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
direction: undefined
|
||||
};
|
||||
|
||||
candle.min = candlesFile[i][0];
|
||||
candle.max = candlesFile[i][1];
|
||||
|
||||
candle.open = candlesFile[i][2];
|
||||
candle.close = candlesFile[i][3];
|
||||
|
||||
candle.begin = candlesFile[i][4];
|
||||
candle.end = candlesFile[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'; }
|
||||
|
||||
candles.push(candle);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> buildBands -> addCandlesToSingleArray -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> buildBands -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function calculateBands() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> calculateBands -> Entering function."); }
|
||||
|
||||
let bandsArray = [];
|
||||
let pBArray = [];
|
||||
let numberOfPeriodsBB = 20;
|
||||
let numberOfStandardDeviations = 2;
|
||||
let numberOfPeriodsPB = 10;
|
||||
|
||||
/* Building bands */
|
||||
|
||||
let band;
|
||||
|
||||
for (let i = numberOfPeriodsBB - 1; i < candles.length; i++) { // Go through all the candles to generate a band segment for each of them.
|
||||
|
||||
/* Calculating the bollinger bands. */
|
||||
|
||||
let movingAverage = 0;
|
||||
for (let j = i - numberOfPeriodsBB + 1; j < i + 1; j++) { // go through the last n candles to calculate the moving average.
|
||||
movingAverage = movingAverage + candles[j].close;
|
||||
}
|
||||
movingAverage = movingAverage / numberOfPeriodsBB;
|
||||
|
||||
let standardDeviation = 0;
|
||||
for (let j = i - numberOfPeriodsBB + 1; j < i + 1; j++) { // go through the last n candles to calculate the standard deviation.
|
||||
standardDeviation = standardDeviation + Math.pow(candles[j].close - movingAverage, 2);
|
||||
}
|
||||
standardDeviation = standardDeviation / numberOfPeriodsBB;
|
||||
standardDeviation = Math.sqrt(standardDeviation);
|
||||
if (standardDeviation === 0) { standardDeviation = 0.000000001; } // This is to prevent a division by zero later.
|
||||
|
||||
band = {
|
||||
begin: candles[i].begin,
|
||||
end: candles[i].end,
|
||||
movingAverage: movingAverage,
|
||||
standardDeviation: standardDeviation,
|
||||
deviation: standardDeviation * numberOfStandardDeviations
|
||||
};
|
||||
|
||||
/* Will only add to the array the bands of the current day */
|
||||
|
||||
if (band.begin >= processDate.valueOf()) { bandsArray.push(band); }
|
||||
|
||||
/* Calculating %B */
|
||||
|
||||
let lowerBB;
|
||||
let upperBB;
|
||||
|
||||
lowerBB = band.movingAverage - band.deviation;
|
||||
upperBB = band.movingAverage + band.deviation;
|
||||
|
||||
let value = (candles[i].close - lowerBB) / (upperBB - lowerBB) * 100;
|
||||
|
||||
/* Moving Average Calculation */
|
||||
|
||||
let numberOfPreviousPeriods;
|
||||
let currentPosition = pBArray.length;
|
||||
|
||||
if (currentPosition < numberOfPeriodsPB) { // Avoinding to get into negative array indexes
|
||||
numberOfPreviousPeriods = currentPosition;
|
||||
} else {
|
||||
numberOfPreviousPeriods = numberOfPeriodsPB;
|
||||
}
|
||||
|
||||
movingAverage = 0;
|
||||
for (let j = currentPosition - numberOfPreviousPeriods; j < currentPosition; j++) { // go through the last numberOfPeriodsPBs to calculate the moving average.
|
||||
movingAverage = movingAverage + pBArray[j].value;
|
||||
}
|
||||
movingAverage = movingAverage + value;
|
||||
movingAverage = movingAverage / (numberOfPreviousPeriods + 1);
|
||||
|
||||
let bandwidth = (upperBB - lowerBB) / band.movingAverage;
|
||||
|
||||
let percentageBandwidth = {
|
||||
begin: candles[i].begin,
|
||||
end: candles[i].end,
|
||||
value: value,
|
||||
movingAverage: movingAverage,
|
||||
bandwidth: bandwidth
|
||||
};
|
||||
|
||||
/* Will only add to the array the pBs of the current day */
|
||||
|
||||
if (percentageBandwidth.begin >= processDate.valueOf()) { pBArray.push(percentageBandwidth); }
|
||||
}
|
||||
|
||||
writeBandsFile(bandsArray, pBArray);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> calculateBands -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function writeBandsFile(pBands, pPB) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> writeBandBandsFile -> writeBandsFile -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < pBands.length; i++) {
|
||||
|
||||
let band = pBands[i];
|
||||
|
||||
fileContent = fileContent + separator + '[' +
|
||||
band.begin + "," +
|
||||
band.end + "," +
|
||||
band.movingAverage + "," +
|
||||
band.standardDeviation + "," +
|
||||
band.deviation + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
fileRecordCounter++;
|
||||
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let dateForPath = processDate.getUTCFullYear() + '/' + utilities.pad(processDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(processDate.getUTCDate(), 2);
|
||||
let fileName = 'Data.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + BOLLINGER_BANDS_FOLDER_NAME + "/" + bot.process + "/" + timeFrame + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> writeBandBandsFile -> writeBandsFile -> onFileCreated -> Entering function."); }
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> writeBandBandsFile -> writeBandsFile -> onFileCreated -> Content written = " + fileContent);
|
||||
}
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> writeBandBandsFile -> writeBandsFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const logText = "[WARN] Finished with File @ " + market.baseAsset + "_" + market.quotedAsset + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName + "";
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> writeBandBandsFile -> writeBandsFile -> onFileCreated -> " + logText); }
|
||||
|
||||
writePBFile(pPB);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> writeBandBandsFile -> writeBandsFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> writeBandBandsFile -> writeBandsFile -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writePBFile(pPercentageBandwidths) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> writeBandBandsFile -> writePBFile -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < pPercentageBandwidths.length; i++) {
|
||||
|
||||
let pB = pPercentageBandwidths[i];
|
||||
|
||||
fileContent = fileContent + separator + '[' +
|
||||
pB.begin + "," +
|
||||
pB.end + "," +
|
||||
pB.value + "," +
|
||||
pB.movingAverage + "," +
|
||||
pB.bandwidth + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
fileRecordCounter++;
|
||||
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let dateForPath = processDate.getUTCFullYear() + '/' + utilities.pad(processDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(processDate.getUTCDate(), 2);
|
||||
let fileName = 'Data.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" + bot.process + "/" + timeFrame + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> writeBandBandsFile -> writePBFile -> onFileCreated -> Entering function."); }
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> writeBandBandsFile -> writePBFile -> onFileCreated -> Content written = " + fileContent);
|
||||
}
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> writeBandBandsFile -> writePBFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const logText = "[WARN] Finished with File @ " + market.baseAsset + "_" + market.quotedAsset + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName + "";
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> writeBandBandsFile -> writePBFile -> onFileCreated -> " + logText); }
|
||||
|
||||
controlLoop();
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> writeBandBandsFile -> writePBFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> writeBandBandsFile -> writePBFile -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> loopBody -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> controlLoop -> Entering function."); }
|
||||
|
||||
n++;
|
||||
|
||||
if (n < global.dailyFilePeriods.length) {
|
||||
|
||||
loopBody();
|
||||
|
||||
} else {
|
||||
|
||||
n = 0;
|
||||
|
||||
writeDataRanges(onWritten);
|
||||
|
||||
function onWritten(err) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> controlLoop -> onWritten -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> controlLoop -> onWritten -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
writeStatusReport(processDate, advanceTime);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> controlLoop -> onWritten -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> controlLoop -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> err.message = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeDataRanges(callBack) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); }
|
||||
|
||||
writeDataRange(contextVariables.firstTradeFile, processDate, BOLLINGER_BANDS_FOLDER_NAME, onBandsBandsDataRangeWritten);
|
||||
|
||||
function onBandsBandsDataRangeWritten(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] writeDataRanges -> writeDataRanges -> onBandsBandsDataRangeWritten -> err = " + err.stack);
|
||||
callBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
writeDataRange(contextVariables.firstTradeFile, processDate, PERCENTAGE_BANDWIDTH_FOLDER_NAME, onPercentageBandwidthDataRangeWritten);
|
||||
|
||||
function onPercentageBandwidthDataRangeWritten(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] writeDataRanges -> writeDataRanges -> onBandsBandsDataRangeWritten -> onPercentageBandwidthDataRangeWritten -> err = " + err.stack);
|
||||
callBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
callBack(global.DEFAULT_OK_RESPONSE);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRanges -> err = " + err.stack);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function writeDataRange(pBegin, pEnd, pProductFolder, callBack) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> Entering function."); }
|
||||
|
||||
let dataRange = {
|
||||
begin: pBegin.valueOf(),
|
||||
end: pEnd.valueOf() + ONE_DAY_IN_MILISECONDS
|
||||
};
|
||||
|
||||
let fileContent = JSON.stringify(dataRange);
|
||||
|
||||
let fileName = 'Data.Range.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + pProductFolder + "/" + bot.process;
|
||||
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.stack);
|
||||
callBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent);
|
||||
}
|
||||
|
||||
callBack(global.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> err = " + err.stack);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport(lastFileDate, callBack) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate); }
|
||||
|
||||
try {
|
||||
|
||||
let reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Daily"
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
thisReport.file.lastExecution = bot.processDatetime;
|
||||
thisReport.file.lastFile = lastFileDate;
|
||||
thisReport.file.beginingOfMarket = beginingOfMarket.toUTCString()
|
||||
thisReport.save(callBack);
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> err.message = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"name": "AAToma",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Luis-Fernando-Molina",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
{
|
||||
"displayName": "Bollinger Bands",
|
||||
"codeName": "Bollinger-Bands",
|
||||
"type": "Indicator Bot",
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0,
|
||||
"patch": 0
|
||||
},
|
||||
"dataMine": "Masters",
|
||||
"profilePicture": "Bollinger Bands.png",
|
||||
"processes": [
|
||||
{
|
||||
"name": "Multi-Period-Market",
|
||||
"description": "Produces a single file for each Time Frame covering all the market.",
|
||||
"startMode": {
|
||||
"allMonths": {
|
||||
"run": "false",
|
||||
"minYear": "",
|
||||
"maxYear": ""
|
||||
},
|
||||
"oneMonth": {
|
||||
"run": "false",
|
||||
"year": "",
|
||||
"month": ""
|
||||
},
|
||||
"noTime": {
|
||||
"run": "true"
|
||||
},
|
||||
"fixedInterval": {
|
||||
"run": "false",
|
||||
"interval": 0
|
||||
}
|
||||
},
|
||||
"deadWaitTime": 0,
|
||||
"normalWaitTime": 0,
|
||||
"retryWaitTime": 10000,
|
||||
"sleepWaitTime": 3600000,
|
||||
"comaWaitTime": 86400000,
|
||||
"updatesDatasets": [
|
||||
{
|
||||
"product": "Bollinger-Bands",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
},
|
||||
{
|
||||
"product": "Percentage-Bandwidth",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
}
|
||||
],
|
||||
"statusDependencies": [
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Bollinger-Bands",
|
||||
"process": "Multi-Period-Market"
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Candles-Volumes",
|
||||
"process": "Multi-Period-Market",
|
||||
"waitUntilNextUpdate": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Multi-Period-Daily",
|
||||
"description": "Produces a Daily File at each Time Frame.",
|
||||
"startMode": {
|
||||
"allMonths": {
|
||||
"run": "false",
|
||||
"minYear": "",
|
||||
"maxYear": ""
|
||||
},
|
||||
"oneMonth": {
|
||||
"run": "false",
|
||||
"year": "",
|
||||
"month": ""
|
||||
},
|
||||
"noTime": {
|
||||
"run": "true"
|
||||
},
|
||||
"fixedInterval": {
|
||||
"run": "false",
|
||||
"interval": 0
|
||||
}
|
||||
},
|
||||
"deadWaitTime": 0,
|
||||
"normalWaitTime": 0,
|
||||
"retryWaitTime": 10000,
|
||||
"sleepWaitTime": 3600000,
|
||||
"comaWaitTime": 86400000,
|
||||
"updatesDatasets": [
|
||||
{
|
||||
"product": "Bollinger-Bands",
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
},
|
||||
{
|
||||
"product": "Percentage-Bandwidth",
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
}
|
||||
],
|
||||
"statusDependencies": [
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Historic-Trades"
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Candles-Volumes",
|
||||
"process": "Multi-Period-Daily",
|
||||
"waitUntilNextUpdate": true
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Bollinger-Bands",
|
||||
"process": "Multi-Period-Daily"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"products": [
|
||||
{
|
||||
"codeName": "Bollinger-Bands",
|
||||
"displayName": "Bollinger Bands",
|
||||
"description": "Bollinger Bands",
|
||||
"storageAccount": "Bollinger-Bands",
|
||||
"shareWith": "Public",
|
||||
"dataSets": [
|
||||
{
|
||||
"codeName": "Multi-Period-Market",
|
||||
"type": "Market Files",
|
||||
"validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ],
|
||||
"filePath": "Masters/Bollinger-Bands.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Bollinger-Bands/Multi-Period-Market/@Period",
|
||||
"fileName": "@AssetA_@AssetB.json"
|
||||
},
|
||||
{
|
||||
"codeName": "Multi-Period-Daily",
|
||||
"type": "Daily Files",
|
||||
"validPeriods": [ "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ],
|
||||
"filePath": "Masters/Bollinger-Bands.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Bollinger-Bands/Multi-Period-Daily/@Period/@Year/@Month/@Day",
|
||||
"fileName": "@AssetA_@AssetB.json",
|
||||
"dataRange": {
|
||||
"filePath": "Masters/Bollinger-Bands.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Bollinger-Bands/Multi-Period-Daily",
|
||||
"fileName": "Data.Range.@AssetA_@AssetB.json"
|
||||
}
|
||||
}
|
||||
],
|
||||
"exchangeList": [
|
||||
{
|
||||
"name": "Poloniex"
|
||||
},
|
||||
{
|
||||
"name": "Coss"
|
||||
}
|
||||
],
|
||||
"plotter": {
|
||||
"dataMine": "Masters",
|
||||
"codeName": "PlottersBollingerBands",
|
||||
"moduleName": "BollingerBands"
|
||||
}
|
||||
},
|
||||
{
|
||||
"codeName": "Percentage-Bandwidth",
|
||||
"displayName": "Percentage Bandwidth",
|
||||
"description": "Percentage Bandwidth",
|
||||
"storageAccount": "Bollinger-Bands",
|
||||
"shareWith": "Public",
|
||||
"dataSets": [
|
||||
{
|
||||
"codeName": "Multi-Period-Market",
|
||||
"type": "Market Files",
|
||||
"validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ],
|
||||
"filePath": "Masters/Bollinger-Bands.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Percentage-Bandwidth/Multi-Period-Market/@Period",
|
||||
"fileName": "@AssetA_@AssetB.json"
|
||||
},
|
||||
{
|
||||
"codeName": "Multi-Period-Daily",
|
||||
"type": "Daily Files",
|
||||
"validPeriods": [ "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ],
|
||||
"filePath": "Masters/Bollinger-Bands.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Percentage-Bandwidth/Multi-Period-Daily/@Period/@Year/@Month/@Day",
|
||||
"fileName": "@AssetA_@AssetB.json",
|
||||
"dataRange": {
|
||||
"filePath": "Masters/Bollinger-Bands.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Percentage-Bandwidth/Multi-Period-Daily",
|
||||
"fileName": "Data.Range.@AssetA_@AssetB.json"
|
||||
}
|
||||
}
|
||||
],
|
||||
"exchangeList": [
|
||||
{
|
||||
"name": "Poloniex"
|
||||
},
|
||||
{
|
||||
"name": "Coss"
|
||||
}
|
||||
],
|
||||
"plotter": {
|
||||
"dataMine": "Masters",
|
||||
"codeName": "PlottersBollingerBands",
|
||||
"moduleName": "PercentageBandwidth"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
// Nothing here to run
|
||||
@@ -1,812 +0,0 @@
|
||||
exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_STORAGE) {
|
||||
|
||||
const FULL_LOG = true;
|
||||
const LOG_FILE_CONTENT = false;
|
||||
|
||||
const GMT_SECONDS = ':00.000 GMT+0000';
|
||||
const GMT_MILI_SECONDS = '.000 GMT+0000';
|
||||
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
|
||||
|
||||
const MODULE_NAME = "User Bot";
|
||||
|
||||
const TRADES_FOLDER_NAME = "Trades";
|
||||
|
||||
const CANDLES_FOLDER_NAME = "Candles";
|
||||
const CANDLES_ONE_MIN = "One-Min";
|
||||
|
||||
const VOLUMES_FOLDER_NAME = "Volumes";
|
||||
const VOLUMES_ONE_MIN = "One-Min";
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
start: start
|
||||
};
|
||||
|
||||
let utilities = UTILITIES.newCloudUtilities(bot, logger);
|
||||
let fileStorage = FILE_STORAGE.newFileStorage(logger);
|
||||
|
||||
let statusDependencies;
|
||||
let beginingOfMarket
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
logger.fileName = MODULE_NAME;
|
||||
logger.initialize();
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
This process is going to do the following:
|
||||
|
||||
Read the candles and volumes from Exchange Raw Data and produce a file for each day and for each period with candles and volumes.
|
||||
|
||||
*/
|
||||
|
||||
function start(callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
|
||||
|
||||
let market = bot.market;
|
||||
|
||||
/* Context Variables */
|
||||
|
||||
let contextVariables = {
|
||||
lastCandleFile: undefined, // Datetime of the last file files sucessfully produced by this process.
|
||||
firstTradeFile: undefined, // Datetime of the first trade file in the whole market history.
|
||||
maxCandleFile: undefined // Datetime of the last file available to be used as an input of this process.
|
||||
};
|
||||
|
||||
getContextVariables();
|
||||
|
||||
function getContextVariables() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Entering function."); }
|
||||
|
||||
let thisReport;
|
||||
let reportKey;
|
||||
let statusReport;
|
||||
|
||||
/* We look first for Exchange Raw Data in order to get when the market starts. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.beginingOfMarket === undefined) {
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet.");
|
||||
|
||||
let customOK = {
|
||||
result: global.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency does not exist."
|
||||
}
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
||||
callBackFunction(customOK);
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.firstTradeFile = new Date(thisReport.beginingOfMarket.year + "-" + thisReport.beginingOfMarket.month + "-" + thisReport.beginingOfMarket.days + " " + thisReport.beginingOfMarket.hours + ":" + thisReport.beginingOfMarket.minutes + GMT_SECONDS);
|
||||
|
||||
/* Second, we get the report from Exchange Raw Data, to know when the marted ends. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile === undefined) {
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
|
||||
let customOK = {
|
||||
result: global.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency not ready."
|
||||
}
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
||||
callBackFunction(customOK);
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.maxCandleFile = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + "00:00" + GMT_SECONDS);
|
||||
|
||||
/* Finally we get our own Status Report. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.");
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile !== undefined) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Process Running not for the very first time. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(thisReport.beginingOfMarket);
|
||||
|
||||
if (beginingOfMarket.valueOf() !== contextVariables.firstTradeFile.valueOf()) { // Reset Mechanism for Begining of the Market
|
||||
logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Reset Mechanism for Begining of the Market Activated. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well.
|
||||
|
||||
buildCandles();
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.lastCandleFile = new Date(thisReport.lastFile);
|
||||
|
||||
/*
|
||||
Here we assume that the last day written might contain incomplete information. This actually happens every time the head of the market is reached.
|
||||
For that reason we go back one day, the partial information is discarded and added again with whatever new info is available.
|
||||
*/
|
||||
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() - ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
buildCandles();
|
||||
return;
|
||||
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Process Running for the very first time. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well.
|
||||
|
||||
buildCandles();
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.stack);
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ");
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
|
||||
}
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function buildCandles() {
|
||||
|
||||
try {
|
||||
let fromDate = new Date(contextVariables.lastCandleFile.valueOf())
|
||||
let lastDate = new Date()
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> Entering function."); }
|
||||
|
||||
let outputCandles;
|
||||
let outputVolumes;
|
||||
|
||||
advanceTime();
|
||||
|
||||
function advanceTime() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> advanceTime -> Entering function."); }
|
||||
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() + ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> advanceTime -> New processing time @ " + contextVariables.lastCandleFile.getUTCFullYear() + "/" + (contextVariables.lastCandleFile.getUTCMonth() + 1) + "/" + contextVariables.lastCandleFile.getUTCDate() + "."); }
|
||||
|
||||
/* Validation that we are not going past the head of the market. */
|
||||
|
||||
if (contextVariables.lastCandleFile.valueOf() > contextVariables.maxCandleFile.valueOf()) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> advanceTime -> Head of the market found @ " + contextVariables.lastCandleFile.getUTCFullYear() + "/" + (contextVariables.lastCandleFile.getUTCMonth() + 1) + "/" + contextVariables.lastCandleFile.getUTCDate() + "."); }
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE); // Here is where we finish processing and wait for the platform to run this module again.
|
||||
return;
|
||||
}
|
||||
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString = contextVariables.lastCandleFile.getUTCFullYear() + '-' + utilities.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '-' + utilities.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let currentDate = new Date(contextVariables.lastCandleFile)
|
||||
let percentage = global.getPercentage(fromDate, currentDate, lastDate)
|
||||
bot.processHeartBeat(currentDateString, percentage)
|
||||
|
||||
if (global.areEqualDates(currentDate, new Date()) === false) {
|
||||
logger.newInternalLoop(bot.codeName, bot.process, currentDate, percentage);
|
||||
}
|
||||
/*
|
||||
|
||||
We prepere the arrays that will accumulate all the information for each output file.
|
||||
|
||||
*/
|
||||
|
||||
outputCandles = [];
|
||||
outputVolumes = [];
|
||||
|
||||
for (let n = 0; n < global.dailyFilePeriods.length; n++) {
|
||||
|
||||
const emptyArray1 = [];
|
||||
const emptyArray2 = [];
|
||||
|
||||
outputCandles.push(emptyArray1);
|
||||
outputVolumes.push(emptyArray2);
|
||||
|
||||
}
|
||||
|
||||
periodsLoop();
|
||||
|
||||
}
|
||||
|
||||
function periodsLoop() {
|
||||
|
||||
/*
|
||||
|
||||
We will iterate through all posible periods.
|
||||
|
||||
*/
|
||||
|
||||
let n = 0 // loop Variable representing each possible period as defined at the periods array.
|
||||
|
||||
loopBody();
|
||||
|
||||
function loopBody() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> Entering function."); }
|
||||
|
||||
const outputPeriod = global.dailyFilePeriods[n][0];
|
||||
const timeFrame = global.dailyFilePeriods[n][1];
|
||||
|
||||
nextCandleFile();
|
||||
|
||||
function nextCandleFile() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> Entering function."); }
|
||||
|
||||
let dateForPath = contextVariables.lastCandleFile.getUTCFullYear() + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
|
||||
let filePathRoot = 'Project/' + bot.project + "/" + bot.mineType + "/" + bot.dataMine + "/" + "Exchange-Raw-Data" + '/' + bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset
|
||||
let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + CANDLES_ONE_MIN + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> getting file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> text = " + text); }
|
||||
|
||||
let candlesFile;
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
candlesFile = JSON.parse(text);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Error Parsing JSON -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (err.message === 'File does not exist.' || err.code === 'The specified key does not exist.') {
|
||||
|
||||
logger.write(MODULE_NAME, "[WARN] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Dependency Not Ready -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[WARN] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Error Received -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const inputCandlesPerdiod = 60 * 1000; // 1 min
|
||||
const inputFilePeriod = 24 * 60 * 60 * 1000; // 24 hs
|
||||
|
||||
let totalOutputCandles = inputFilePeriod / outputPeriod;
|
||||
let beginingOutputTime = contextVariables.lastCandleFile.valueOf();
|
||||
|
||||
for (let i = 0; i < totalOutputCandles; i++) {
|
||||
|
||||
let outputCandle = {
|
||||
open: 0,
|
||||
close: 0,
|
||||
min: 0,
|
||||
max: 0,
|
||||
begin: 0,
|
||||
end: 0
|
||||
};
|
||||
|
||||
let saveCandle = false;
|
||||
|
||||
outputCandle.begin = beginingOutputTime + i * outputPeriod;
|
||||
outputCandle.end = beginingOutputTime + (i + 1) * outputPeriod - 1;
|
||||
|
||||
for (let j = 0; j < candlesFile.length; j++) {
|
||||
|
||||
let candle = {
|
||||
open: candlesFile[j][2],
|
||||
close: candlesFile[j][3],
|
||||
min: candlesFile[j][0],
|
||||
max: candlesFile[j][1],
|
||||
begin: candlesFile[j][4],
|
||||
end: candlesFile[j][5]
|
||||
};
|
||||
|
||||
/* Here we discard all the candles out of range. */
|
||||
|
||||
if (candle.begin >= outputCandle.begin && candle.end <= outputCandle.end) {
|
||||
|
||||
if (saveCandle === false) { // this will set the value only once.
|
||||
|
||||
outputCandle.open = candle.open;
|
||||
outputCandle.min = candle.min;
|
||||
outputCandle.max = candle.max;
|
||||
}
|
||||
|
||||
saveCandle = true;
|
||||
|
||||
outputCandle.close = candle.close; // only the last one will be saved
|
||||
|
||||
if (candle.min < outputCandle.min) {
|
||||
|
||||
outputCandle.min = candle.min;
|
||||
}
|
||||
|
||||
if (candle.max > outputCandle.max) {
|
||||
|
||||
outputCandle.max = candle.max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (saveCandle === true) { // then we have a valid candle, otherwise it means there were no candles to fill this one in its time range.
|
||||
|
||||
outputCandles[n].push(outputCandle);
|
||||
}
|
||||
}
|
||||
|
||||
nextVolumeFile();
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function nextVolumeFile() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> Entering function."); }
|
||||
|
||||
let dateForPath = contextVariables.lastCandleFile.getUTCFullYear() + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
|
||||
let filePathRoot = 'Project/' + bot.project + "/" + bot.mineType + "/" + bot.dataMine + "/" + "Exchange-Raw-Data" + '/' + bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset
|
||||
let filePath = filePathRoot + "/Output/" + VOLUMES_FOLDER_NAME + '/' + VOLUMES_ONE_MIN + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> getting file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> text = " + text); }
|
||||
|
||||
let volumesFile;
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
volumesFile = JSON.parse(text);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Error Parsing JSON -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Error Received -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const inputVolumesPerdiod = 60 * 1000; // 1 min
|
||||
const inputFilePeriod = 24 * 60 * 60 * 1000; // 24 hs
|
||||
|
||||
let totalOutputVolumes = inputFilePeriod / outputPeriod; // this should be 2 in this case.
|
||||
let beginingOutputTime = contextVariables.lastCandleFile.valueOf();
|
||||
|
||||
for (let i = 0; i < totalOutputVolumes; i++) {
|
||||
|
||||
let outputVolume = {
|
||||
buy: 0,
|
||||
sell: 0,
|
||||
begin: 0,
|
||||
end: 0
|
||||
};
|
||||
|
||||
let saveVolume = false;
|
||||
|
||||
outputVolume.begin = beginingOutputTime + i * outputPeriod;
|
||||
outputVolume.end = beginingOutputTime + (i + 1) * outputPeriod - 1;
|
||||
|
||||
for (let j = 0; j < volumesFile.length; j++) {
|
||||
|
||||
let volume = {
|
||||
buy: volumesFile[j][0],
|
||||
sell: volumesFile[j][1],
|
||||
begin: volumesFile[j][2],
|
||||
end: volumesFile[j][3]
|
||||
};
|
||||
|
||||
/* Here we discard all the Volumes out of range. */
|
||||
|
||||
if (volume.begin >= outputVolume.begin && volume.end <= outputVolume.end) {
|
||||
|
||||
saveVolume = true;
|
||||
|
||||
outputVolume.buy = outputVolume.buy + volume.buy;
|
||||
outputVolume.sell = outputVolume.sell + volume.sell;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (saveVolume === true) {
|
||||
|
||||
outputVolumes[n].push(outputVolume);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
writeFiles(outputCandles[n], outputVolumes[n], timeFrame, controlLoop);
|
||||
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> controlLoop -> Entering function."); }
|
||||
|
||||
n++;
|
||||
|
||||
if (n < global.dailyFilePeriods.length) {
|
||||
|
||||
loopBody();
|
||||
|
||||
} else {
|
||||
|
||||
writeDataRanges(onWritten);
|
||||
|
||||
function onWritten(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> controlLoop -> onWritten -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] writeDataRanges -> writeDataRanges -> onCandlesDataRangeWritten -> err = " + err.stack);
|
||||
callBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
writeStatusReport(contextVariables.lastCandleFile, advanceTime);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeFiles(candles, volumes, timeFrame, callBack) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> Entering function."); }
|
||||
|
||||
/*
|
||||
|
||||
Here we will write the contents of the Candles and Volumens files.
|
||||
|
||||
*/
|
||||
|
||||
try {
|
||||
|
||||
writeCandles();
|
||||
|
||||
function writeCandles() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
|
||||
let candle = candles[i];
|
||||
|
||||
fileContent = fileContent + separator + '[' + candles[i].min + "," + candles[i].max + "," + candles[i].open + "," + candles[i].close + "," + candles[i].begin + "," + candles[i].end + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
fileRecordCounter++;
|
||||
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let dateForPath = contextVariables.lastCandleFile.getUTCFullYear() + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let filePath = bot.filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + bot.process + "/" + timeFrame + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> creating file at filePath = " + filePath);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> onFileCreated -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeCandles -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> onFileCreated -> Content written = " + fileContent);
|
||||
}
|
||||
|
||||
logger.write(MODULE_NAME, "[WARN] start -> writeFiles -> writeCandles -> onFileCreated -> Finished with File @ " + market.baseAsset + "_" + market.quotedAsset + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName);
|
||||
|
||||
writeVolumes();
|
||||
}
|
||||
}
|
||||
|
||||
function writeVolumes() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < volumes.length; i++) {
|
||||
|
||||
let candle = volumes[i];
|
||||
|
||||
fileContent = fileContent + separator + '[' + volumes[i].buy + "," + volumes[i].sell + "," + volumes[i].begin + "," + volumes[i].end + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
fileRecordCounter++;
|
||||
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let dateForPath = contextVariables.lastCandleFile.getUTCFullYear() + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let filePath = bot.filePathRoot + "/Output/" + VOLUMES_FOLDER_NAME + "/" + bot.process + "/" + timeFrame + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> creating file at filePath = " + filePath);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> onFileCreated -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeVolumes -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> onFileCreated -> Content written = " + fileContent);
|
||||
}
|
||||
|
||||
logger.write(MODULE_NAME, "[WARN] start -> writeFiles -> writeVolumes -> onFileCreated -> Finished with File @ " + market.baseAsset + "_" + market.quotedAsset + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName);
|
||||
|
||||
callBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeDataRanges(callBack) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); }
|
||||
|
||||
writeDataRange(contextVariables.firstTradeFile, contextVariables.lastCandleFile, CANDLES_FOLDER_NAME, onCandlesDataRangeWritten);
|
||||
|
||||
function onCandlesDataRangeWritten(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] writeDataRanges -> writeDataRanges -> onCandlesDataRangeWritten -> err = " + err.stack);
|
||||
callBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
writeDataRange(contextVariables.firstTradeFile, contextVariables.lastCandleFile, VOLUMES_FOLDER_NAME, onVolumeDataRangeWritten);
|
||||
|
||||
function onVolumeDataRangeWritten(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] writeDataRanges -> writeDataRanges -> onVolumeDataRangeWritten -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] writeDataRanges -> writeDataRanges -> onVolumeDataRangeWritten -> err = " + err.stack);
|
||||
callBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
callBack(global.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRanges -> err = " + err.stack);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function writeDataRange(pBegin, pEnd, pProductFolder, callBack) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> Entering function."); }
|
||||
|
||||
let dataRange = {
|
||||
begin: pBegin.valueOf(),
|
||||
end:pEnd.valueOf() + ONE_DAY_IN_MILISECONDS
|
||||
};
|
||||
|
||||
let fileContent = JSON.stringify(dataRange);
|
||||
|
||||
let fileName = 'Data.Range.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + pProductFolder + "/" + bot.process;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.stack);
|
||||
callBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent);
|
||||
}
|
||||
|
||||
let key = bot.dataMine + "-" + bot.codeName + "-" + pProductFolder + "-" + bot.exchange + "-" + bot.market.baseAsset + '/' + bot.market.quotedAsset
|
||||
let event = {
|
||||
dateRange: dataRange
|
||||
}
|
||||
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Data Range Updated', event)
|
||||
|
||||
callBack(global.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> err = " + err.stack);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport(lastFileDate, callBack) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate); }
|
||||
|
||||
try {
|
||||
|
||||
let reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily"
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
thisReport.file.lastExecution = bot.processDatetime;
|
||||
thisReport.file.lastFile = lastFileDate;
|
||||
thisReport.file.beginingOfMarket = beginingOfMarket.toUTCString()
|
||||
thisReport.save(callBack);
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] 'Start' - ERROR : " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,929 +0,0 @@
|
||||
exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_STORAGE) {
|
||||
|
||||
const FULL_LOG = true;
|
||||
const LOG_FILE_CONTENT = false;
|
||||
|
||||
const GMT_SECONDS = ':00.000 GMT+0000';
|
||||
const GMT_MILI_SECONDS = '.000 GMT+0000';
|
||||
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
|
||||
|
||||
const MODULE_NAME = "User Bot";
|
||||
|
||||
const TRADES_FOLDER_NAME = "Trades";
|
||||
|
||||
const CANDLES_FOLDER_NAME = "Candles";
|
||||
const CANDLES_ONE_MIN = "One-Min";
|
||||
|
||||
const VOLUMES_FOLDER_NAME = "Volumes";
|
||||
const VOLUMES_ONE_MIN = "One-Min";
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
start: start
|
||||
};
|
||||
|
||||
let utilities = UTILITIES.newCloudUtilities(bot, logger);
|
||||
let fileStorage = FILE_STORAGE.newFileStorage(logger);
|
||||
|
||||
let statusDependencies;
|
||||
let beginingOfMarket
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
logger.fileName = MODULE_NAME;
|
||||
logger.initialize();
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
This process is going to do the following:
|
||||
|
||||
Read the candles and volumes from Exchange Raw Data and produce a single Index File for Market Period. But this is the situation:
|
||||
|
||||
Exchange Raw Data has a dataset organized with daily files with candles of 1 min. Candles Volumes is writting in this process a single file for each timeFrame for the whole market.
|
||||
Everytime this process run, must be able to resume its job and process everything pending until reaching the head of the market. So the tactic to do this is the
|
||||
following:
|
||||
|
||||
1. First we need to read the last file written by this process, and load all the information into in-memory arrays. We will then append to this arrays the new
|
||||
information we will get from Exchange Raw Data.
|
||||
|
||||
2. We know from out status report which was the last DAY we processed from Exchange Raw Data, but we must be carefull, because that day mightn not have been complete, if the
|
||||
last run found the head of the market. That means that we have to be carefull not to append candles that are already there. To simplify what we do is to discard
|
||||
all candles of the last processed day, and then we can process that full day again adding all the candles.
|
||||
|
||||
*/
|
||||
|
||||
function start(callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
|
||||
|
||||
let market = bot.market;
|
||||
|
||||
/* Context Variables */
|
||||
|
||||
let contextVariables = {
|
||||
lastCandleFile: undefined, // Datetime of the last file files sucessfully produced by this process.
|
||||
firstTradeFile: undefined, // Datetime of the first trade file in the whole market history.
|
||||
maxCandleFile: undefined // Datetime of the last file available to be used as an input of this process.
|
||||
};
|
||||
|
||||
getContextVariables();
|
||||
|
||||
function getContextVariables() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Entering function."); }
|
||||
|
||||
let thisReport;
|
||||
let reportKey;
|
||||
let statusReport;
|
||||
|
||||
/* We look first for Exchange Raw Data in order to get when the market starts. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.beginingOfMarket === undefined) {
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet.");
|
||||
|
||||
let customOK = {
|
||||
result: global.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency does not exist."
|
||||
}
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
||||
callBackFunction(customOK);
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.firstTradeFile = new Date(thisReport.beginingOfMarket.year + "-" + thisReport.beginingOfMarket.month + "-" + thisReport.beginingOfMarket.days + " " + thisReport.beginingOfMarket.hours + ":" + thisReport.beginingOfMarket.minutes + GMT_SECONDS);
|
||||
|
||||
/* Second, we get the report from Exchange Raw Data, to know when the marted ends. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile === undefined) {
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
|
||||
let customOK = {
|
||||
result: global.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency not ready."
|
||||
}
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
||||
callBackFunction(customOK);
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.maxCandleFile = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + "00:00" + GMT_SECONDS);
|
||||
|
||||
/* Finally we get our own Status Report. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Market"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.");
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile !== undefined) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Process Running not for the very first time. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(thisReport.beginingOfMarket);
|
||||
|
||||
if (beginingOfMarket.valueOf() !== contextVariables.firstTradeFile.valueOf()) { // Reset Mechanism for Begining of the Market
|
||||
logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Reset Mechanism for Begining of the Market Activated. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well.
|
||||
|
||||
buildCandles();
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.lastCandleFile = new Date(thisReport.lastFile);
|
||||
|
||||
/*
|
||||
Here we assume that the last day written might contain incomplete information. This actually happens every time the head of the market is reached.
|
||||
For that reason we go back one day, the partial information is discarded and added again with whatever new info is available.
|
||||
*/
|
||||
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() - ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
findPreviousContent();
|
||||
return;
|
||||
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Process Running for the very first time. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well.
|
||||
|
||||
buildCandles();
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.stack);
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ");
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> Double check that you are not running a process that only can be run at noTime mode at a certain month when it is not prepared to do so.");
|
||||
}
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function findPreviousContent() {
|
||||
|
||||
/*
|
||||
This is where we read the current files we have produced at previous runs of this same process. We just read all the content and organize it
|
||||
in arrays and keep them in memory.
|
||||
*/
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> Entering function."); }
|
||||
|
||||
let n = 0 // loop Variable representing each possible period as defined at the periods array.
|
||||
|
||||
let allPreviousCandles = [];
|
||||
let allPreviousVolumes = [];
|
||||
|
||||
loopBody();
|
||||
|
||||
function loopBody() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> loopBody -> Entering function."); }
|
||||
|
||||
let timeFrame = global.marketFilesPeriods[n][1];
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> loopBody -> timeFrame = " + timeFrame); }
|
||||
|
||||
let previousCandles;
|
||||
let previousVolumes;
|
||||
|
||||
getCandles();
|
||||
|
||||
function getCandles() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> loopBody -> getCandles -> Entering function."); }
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + bot.process + "/" + timeFrame;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> loopBody -> getCandles -> getting file.");
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> text = " + text); }
|
||||
|
||||
let candlesFile;
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
candlesFile = JSON.parse(text);
|
||||
|
||||
previousCandles = candlesFile;
|
||||
|
||||
getVolumes();
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> fileName = " + fileName);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
}
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getVolumes() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> loopBody -> getVolumes -> Entering function."); }
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + VOLUMES_FOLDER_NAME + "/" + bot.process + "/" + timeFrame;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> loopBody -> getVolumes -> getting file.");
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> text = " + text); }
|
||||
|
||||
let volumesFile;
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
volumesFile = JSON.parse(text);
|
||||
|
||||
previousVolumes = volumesFile;
|
||||
|
||||
allPreviousCandles.push(previousCandles);
|
||||
allPreviousVolumes.push(previousVolumes);
|
||||
|
||||
controlLoop();
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> fileName = " + fileName);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
}
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> controlLoop -> Entering function."); }
|
||||
|
||||
n++;
|
||||
|
||||
if (n < global.marketFilesPeriods.length) {
|
||||
|
||||
loopBody();
|
||||
|
||||
} else {
|
||||
|
||||
buildCandles(allPreviousCandles, allPreviousVolumes);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function buildCandles(allPreviousCandles, allPreviousVolumes) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> Entering function."); }
|
||||
|
||||
let fromDate = new Date(contextVariables.lastCandleFile.valueOf())
|
||||
let lastDate = new Date()
|
||||
|
||||
/*
|
||||
Firstly we prepere the arrays that will accumulate all the information for each output file.
|
||||
*/
|
||||
|
||||
let outputCandles = [];
|
||||
let outputVolumes = [];
|
||||
|
||||
for (let n = 0; n < global.marketFilesPeriods.length; n++) {
|
||||
|
||||
const emptyArray1 = [];
|
||||
const emptyArray2 = [];
|
||||
|
||||
outputCandles.push(emptyArray1);
|
||||
outputVolumes.push(emptyArray2);
|
||||
|
||||
}
|
||||
|
||||
advanceTime();
|
||||
|
||||
function advanceTime() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> advanceTime -> Entering function."); }
|
||||
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() + ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> advanceTime -> New processing time @ " + contextVariables.lastCandleFile.getUTCFullYear() + "/" + (contextVariables.lastCandleFile.getUTCMonth() + 1) + "/" + contextVariables.lastCandleFile.getUTCDate() + "."); }
|
||||
|
||||
/* Validation that we are not going past the head of the market. */
|
||||
|
||||
if (contextVariables.lastCandleFile.valueOf() > contextVariables.maxCandleFile.valueOf()) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> advanceTime -> Head of the market found @ " + contextVariables.lastCandleFile.getUTCFullYear() + "/" + (contextVariables.lastCandleFile.getUTCMonth() + 1) + "/" + contextVariables.lastCandleFile.getUTCDate() + "."); }
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE); // Here is where we finish processing and wait for the platform to run this module again.
|
||||
return;
|
||||
}
|
||||
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString = contextVariables.lastCandleFile.getUTCFullYear() + '-' + utilities.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '-' + utilities.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let currentDate = new Date(contextVariables.lastCandleFile)
|
||||
let percentage = global.getPercentage(fromDate, currentDate, lastDate)
|
||||
bot.processHeartBeat(currentDateString, percentage)
|
||||
|
||||
if (global.areEqualDates(currentDate, new Date()) === false) {
|
||||
logger.newInternalLoop(bot.codeName, bot.process, currentDate, percentage);
|
||||
}
|
||||
|
||||
periodsLoop();
|
||||
|
||||
}
|
||||
|
||||
function periodsLoop() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> Entering function."); }
|
||||
|
||||
/*
|
||||
|
||||
We will iterate through all posible periods.
|
||||
|
||||
*/
|
||||
|
||||
let n = 0 // loop Variable representing each possible period as defined at the periods array.
|
||||
|
||||
loopBody();
|
||||
|
||||
function loopBody() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> Entering function."); }
|
||||
|
||||
let previousCandles;
|
||||
let previousVolumes;
|
||||
|
||||
if (allPreviousCandles !== undefined) {
|
||||
|
||||
previousCandles = allPreviousCandles[n];
|
||||
previousVolumes = allPreviousVolumes[n];
|
||||
|
||||
}
|
||||
|
||||
const outputPeriod = global.marketFilesPeriods[n][0];
|
||||
const timeFrame = global.marketFilesPeriods[n][1];
|
||||
|
||||
/*
|
||||
Here we are inside a Loop that is going to advance 1 day at the time, at each pass, will ready one of Exchange Raw Data's daily files and
|
||||
add all its candles to our in memory arrays. At the first iteration of this loop, we will add the candles that we are carrying
|
||||
from our previous run, the ones we already have in-memory. You can see below how we discard from those candles the ones that
|
||||
are belonging to the first day we are processing at this run, that it is exactly the same as the last day processed the privious
|
||||
run. By discarding these candles, we are ready to run after that standard function that will just add ALL the candles found each
|
||||
day at Exchange Raw Data.
|
||||
*/
|
||||
|
||||
if (previousCandles !== undefined) {
|
||||
|
||||
for (let i = 0; i < previousCandles.length; i++) {
|
||||
|
||||
let candle = {
|
||||
open: previousCandles[i][2],
|
||||
close: previousCandles[i][3],
|
||||
min: previousCandles[i][0],
|
||||
max: previousCandles[i][1],
|
||||
begin: previousCandles[i][4],
|
||||
end: previousCandles[i][5]
|
||||
};
|
||||
|
||||
if (candle.end < contextVariables.lastCandleFile.valueOf()) {
|
||||
|
||||
outputCandles[n].push(candle);
|
||||
|
||||
} else {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> Candle # " + i + " @ " + timeFrame + " discarded for closing past the current process time."); }
|
||||
}
|
||||
}
|
||||
allPreviousCandles[n] = []; // erasing these so as not to duplicate them.
|
||||
}
|
||||
|
||||
if (previousVolumes !== undefined) {
|
||||
|
||||
for (let i = 0; i < previousVolumes.length; i++) {
|
||||
|
||||
let volume = {
|
||||
begin: previousVolumes[i][2],
|
||||
end: previousVolumes[i][3],
|
||||
buy: previousVolumes[i][0],
|
||||
sell: previousVolumes[i][1]
|
||||
};
|
||||
|
||||
if (volume.end < contextVariables.lastCandleFile.valueOf()) {
|
||||
|
||||
outputVolumes[n].push(volume);
|
||||
|
||||
} else {
|
||||
if (FULL_LOG === true) {logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> Volume # " + i + " @ " + timeFrame + " discarded for closing past the current process time."); }
|
||||
}
|
||||
}
|
||||
allPreviousVolumes[n] = []; // erasing these so as not to duplicate them.
|
||||
}
|
||||
|
||||
/*
|
||||
From here on is where every iteration of the loop fully runs. Here is where we read Exchange Raw Data's files and add their content to whatever
|
||||
we already have in our arrays in-memory. In this way the process will run as many days needed and it should only stop when it reaches
|
||||
the head of the market.
|
||||
*/
|
||||
|
||||
nextCandleFile();
|
||||
|
||||
function nextCandleFile() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> Entering function."); }
|
||||
|
||||
let dateForPath = contextVariables.lastCandleFile.getUTCFullYear() + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
|
||||
let filePathRoot = 'Project/' + bot.project + "/" + bot.mineType + "/" + bot.dataMine + "/" + "Exchange-Raw-Data" + '/' + bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset
|
||||
let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + CANDLES_ONE_MIN + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> getting file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> text = " + text); }
|
||||
|
||||
let candlesFile;
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
candlesFile = JSON.parse(text);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Error Parsing JSON -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (err.message === 'File does not exist.' || err.code === 'The specified key does not exist.') {
|
||||
|
||||
logger.write(MODULE_NAME, "[WARN] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Dependency Not Ready -> err = " + JSON.stringify(err));
|
||||
logger.write(MODULE_NAME, "[WARN] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Error Received -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const inputCandlesPerdiod = 60 * 1000; // 1 min
|
||||
const inputFilePeriod = 24 * 60 * 60 * 1000; // 24 hs
|
||||
|
||||
let totalOutputCandles = inputFilePeriod / outputPeriod; // this should be 2 in this case.
|
||||
let beginingOutputTime = contextVariables.lastCandleFile.valueOf();
|
||||
|
||||
/*
|
||||
The algorithm that follows is going to agregate candles of 1 min timeFrame read from Exchange Raw Data, into candles of each timeFrame
|
||||
that Candles Volumes generates. For market files those timePediods goes from 1h to 24hs.
|
||||
*/
|
||||
|
||||
for (let i = 0; i < totalOutputCandles; i++) {
|
||||
|
||||
let outputCandle = {
|
||||
open: 0,
|
||||
close: 0,
|
||||
min: 0,
|
||||
max: 0,
|
||||
begin: 0,
|
||||
end: 0
|
||||
};
|
||||
|
||||
let saveCandle = false;
|
||||
|
||||
outputCandle.begin = beginingOutputTime + i * outputPeriod;
|
||||
outputCandle.end = beginingOutputTime + (i + 1) * outputPeriod - 1;
|
||||
|
||||
for (let j = 0; j < candlesFile.length; j++) {
|
||||
|
||||
let candle = {
|
||||
open: candlesFile[j][2],
|
||||
close: candlesFile[j][3],
|
||||
min: candlesFile[j][0],
|
||||
max: candlesFile[j][1],
|
||||
begin: candlesFile[j][4],
|
||||
end: candlesFile[j][5]
|
||||
};
|
||||
|
||||
/* Here we discard all the candles out of range. */
|
||||
|
||||
if (candle.begin >= outputCandle.begin && candle.end <= outputCandle.end) {
|
||||
|
||||
if (saveCandle === false) { // this will set the value only once.
|
||||
|
||||
outputCandle.open = candle.open;
|
||||
outputCandle.min = candle.min;
|
||||
outputCandle.max = candle.max;
|
||||
}
|
||||
|
||||
saveCandle = true;
|
||||
|
||||
outputCandle.close = candle.close; // only the last one will be saved
|
||||
|
||||
if (candle.min < outputCandle.min) {
|
||||
|
||||
outputCandle.min = candle.min;
|
||||
}
|
||||
|
||||
if (candle.max > outputCandle.max) {
|
||||
|
||||
outputCandle.max = candle.max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (saveCandle === true) { // then we have a valid candle, otherwise it means there were no candles to fill this one in its time range.
|
||||
|
||||
outputCandles[n].push(outputCandle);
|
||||
}
|
||||
}
|
||||
|
||||
nextVolumeFile();
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function nextVolumeFile() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> Entering function."); }
|
||||
|
||||
let dateForPath = contextVariables.lastCandleFile.getUTCFullYear() + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' + utilities.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
|
||||
let filePathRoot = 'Project/' + bot.project + "/" + bot.mineType + "/" + bot.dataMine + "/" + "Exchange-Raw-Data" + '/' + bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset
|
||||
let filePath = filePathRoot + "/Output/" + VOLUMES_FOLDER_NAME + '/' + VOLUMES_ONE_MIN + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> getting file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> text = " + text); }
|
||||
|
||||
let volumesFile;
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
volumesFile = JSON.parse(text);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Error Parsing JSON -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Error Received -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const inputVolumesPerdiod = 60 * 1000; // 1 min
|
||||
const inputFilePeriod = 24 * 60 * 60 * 1000; // 24 hs
|
||||
|
||||
let totalOutputVolumes = inputFilePeriod / outputPeriod; // this should be 2 in this case.
|
||||
let beginingOutputTime = contextVariables.lastCandleFile.valueOf();
|
||||
|
||||
for (let i = 0; i < totalOutputVolumes; i++) {
|
||||
|
||||
let outputVolume = {
|
||||
buy: 0,
|
||||
sell: 0,
|
||||
begin: 0,
|
||||
end: 0
|
||||
};
|
||||
|
||||
let saveVolume = false;
|
||||
|
||||
outputVolume.begin = beginingOutputTime + i * outputPeriod;
|
||||
outputVolume.end = beginingOutputTime + (i + 1) * outputPeriod - 1;
|
||||
|
||||
for (let j = 0; j < volumesFile.length; j++) {
|
||||
|
||||
let volume = {
|
||||
buy: volumesFile[j][0],
|
||||
sell: volumesFile[j][1],
|
||||
begin: volumesFile[j][2],
|
||||
end: volumesFile[j][3]
|
||||
};
|
||||
|
||||
/* Here we discard all the Volumes out of range. */
|
||||
|
||||
if (volume.begin >= outputVolume.begin && volume.end <= outputVolume.end) {
|
||||
|
||||
saveVolume = true;
|
||||
|
||||
outputVolume.buy = outputVolume.buy + volume.buy;
|
||||
outputVolume.sell = outputVolume.sell + volume.sell;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (saveVolume === true) {
|
||||
|
||||
outputVolumes[n].push(outputVolume);
|
||||
}
|
||||
}
|
||||
|
||||
writeFiles(outputCandles[n], outputVolumes[n], timeFrame, controlLoop);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandles -> periodsLoop -> controlLoop -> Entering function."); }
|
||||
|
||||
n++;
|
||||
|
||||
if (n < global.marketFilesPeriods.length) {
|
||||
|
||||
loopBody();
|
||||
|
||||
} else {
|
||||
|
||||
writeStatusReport(contextVariables.lastCandleFile, advanceTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandles -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeFiles(candles, volumes, timeFrame, callBack) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> Entering function."); }
|
||||
|
||||
/*
|
||||
|
||||
Here we will write the contents of the Candles and Volumens files.
|
||||
|
||||
*/
|
||||
|
||||
try {
|
||||
|
||||
writeCandles();
|
||||
|
||||
function writeCandles() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
|
||||
let candle = candles[i];
|
||||
|
||||
fileContent = fileContent + separator + '[' + candles[i].min + "," + candles[i].max + "," + candles[i].open + "," + candles[i].close + "," + candles[i].begin + "," + candles[i].end + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
fileRecordCounter++;
|
||||
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + bot.process + "/" + timeFrame;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> creating file at filePath = " + filePath);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> onFileCreated -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeCandles -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> onFileCreated -> Content written = " + fileContent);
|
||||
}
|
||||
|
||||
logger.write(MODULE_NAME, "[WARN] start -> writeFiles -> writeCandles -> onFileCreated -> Finished with File @ " + market.baseAsset + "_" + market.quotedAsset + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName );
|
||||
|
||||
writeVolumes();
|
||||
}
|
||||
}
|
||||
|
||||
function writeVolumes() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < volumes.length; i++) {
|
||||
|
||||
let candle = volumes[i];
|
||||
|
||||
fileContent = fileContent + separator + '[' + volumes[i].buy + "," + volumes[i].sell + "," + volumes[i].begin + "," + volumes[i].end + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
fileRecordCounter++;
|
||||
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + VOLUMES_FOLDER_NAME + "/" + bot.process + "/" + timeFrame;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> creating file at filePath = " + filePath);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> onFileCreated -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeVolumes -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> onFileCreated -> Content written = " + fileContent);
|
||||
}
|
||||
|
||||
logger.write(MODULE_NAME, "[WARN] start -> writeFiles -> writeVolumes -> onFileCreated -> Finished with File @ " + market.baseAsset + "_" + market.quotedAsset + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName);
|
||||
|
||||
callBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport(lastFileDate, callBack) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate); }
|
||||
|
||||
try {
|
||||
|
||||
let reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Market"
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
thisReport.file.lastExecution = bot.processDatetime;
|
||||
thisReport.file.lastFile = lastFileDate;
|
||||
thisReport.file.beginingOfMarket = beginingOfMarket.toUTCString()
|
||||
thisReport.save(callBack);
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "AAOlivia",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Luis-Fernando-Molina",
|
||||
"license": "ISC",
|
||||
"dependencies": {}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
{
|
||||
"displayName": "Candles Volumes",
|
||||
"codeName": "Candles-Volumes",
|
||||
"type": "Indicator Bot",
|
||||
"dataMine": "Masters",
|
||||
"processes": [
|
||||
{
|
||||
"name": "Multi-Period-Market",
|
||||
"description": "Produces different files with multi-period candles and volumes for entire markets.",
|
||||
"startMode": {
|
||||
"allMonths": {
|
||||
"run": "false",
|
||||
"minYear": "",
|
||||
"maxYear": ""
|
||||
},
|
||||
"oneMonth": {
|
||||
"run": "false",
|
||||
"year": "",
|
||||
"month": ""
|
||||
},
|
||||
"noTime": {
|
||||
"run": "true"
|
||||
},
|
||||
"fixedInterval": {
|
||||
"run": "false",
|
||||
"interval": 0
|
||||
}
|
||||
},
|
||||
"deadWaitTime": 0,
|
||||
"normalWaitTime": 0,
|
||||
"retryWaitTime": 10000,
|
||||
"sleepWaitTime": 3600000,
|
||||
"comaWaitTime": 86400000,
|
||||
"updatesDatasets": [
|
||||
{
|
||||
"product": "Candles",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
},
|
||||
{
|
||||
"product": "Volumes",
|
||||
"dataSet": "Multi-Period-Market"
|
||||
}
|
||||
],
|
||||
"statusDependencies": [
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Historic-OHLCVs"
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Historic-OHLCVs",
|
||||
"dataSetSection": "Month",
|
||||
"waitUntilNextUpdate": true
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Candles-Volumes",
|
||||
"process": "Multi-Period-Market"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Multi-Period-Daily",
|
||||
"description": "Produces different files with multi-period candles and volumes on a daily format.",
|
||||
"startMode": {
|
||||
"allMonths": {
|
||||
"run": "false",
|
||||
"minYear": "",
|
||||
"maxYear": ""
|
||||
},
|
||||
"oneMonth": {
|
||||
"run": "false",
|
||||
"year": "",
|
||||
"month": ""
|
||||
},
|
||||
"noTime": {
|
||||
"run": "true"
|
||||
},
|
||||
"fixedInterval": {
|
||||
"run": "false",
|
||||
"interval": 0
|
||||
}
|
||||
},
|
||||
"deadWaitTime": 0,
|
||||
"normalWaitTime": 0,
|
||||
"retryWaitTime": 10000,
|
||||
"sleepWaitTime": 3600000,
|
||||
"comaWaitTime": 86400000,
|
||||
"updatesDatasets": [
|
||||
{
|
||||
"product": "Candles",
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
},
|
||||
{
|
||||
"product": "Volumes",
|
||||
"dataSet": "Multi-Period-Daily"
|
||||
}
|
||||
],
|
||||
"statusDependencies": [
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Historic-OHLCVs"
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Historic-OHLCVs",
|
||||
"dataSetSection": "Month",
|
||||
"waitUntilNextUpdate": true
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Candles-Volumes",
|
||||
"process": "Multi-Period-Daily"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"products": [
|
||||
{
|
||||
"codeName": "Candles",
|
||||
"displayName": "Candles",
|
||||
"description": "Two sets of files per period that contains candles.",
|
||||
"storageAccount": "Candles-Volumes",
|
||||
"shareWith": "Public",
|
||||
"dataSets": [
|
||||
{
|
||||
"codeName": "Multi-Period-Market",
|
||||
"type": "Market Files",
|
||||
"validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ],
|
||||
"filePath": "Masters/Candles-Volumes.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Candles/Multi-Period-Market/@Period",
|
||||
"fileName": "@AssetA_@AssetB.json"
|
||||
},
|
||||
{
|
||||
"codeName": "Multi-Period-Daily",
|
||||
"type": "Daily Files",
|
||||
"validPeriods": [ "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ],
|
||||
"filePath": "Masters/Candles-Volumes.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Candles/Multi-Period-Daily/@Period/@Year/@Month/@Day",
|
||||
"fileName": "@AssetA_@AssetB.json",
|
||||
"dataRange": {
|
||||
"filePath": "Masters/Candles-Volumes.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Candles/Multi-Period-Daily",
|
||||
"fileName": "Data.Range.@AssetA_@AssetB.json"
|
||||
}
|
||||
}
|
||||
],
|
||||
"exchangeList": [
|
||||
{
|
||||
"name": "Poloniex"
|
||||
},
|
||||
{
|
||||
"name": "Coss"
|
||||
}
|
||||
],
|
||||
"plotter": {
|
||||
"dataMine": "Masters",
|
||||
"codeName": "PlottersCandlesVolumes",
|
||||
"moduleName": "Candles"
|
||||
}
|
||||
},
|
||||
{
|
||||
"codeName": "Volumes",
|
||||
"displayName": "Buy and Sell Volumes",
|
||||
"description": "Two sets of files per period that contains buy and sell volumes.",
|
||||
"storageAccount": "Candles-Volumes",
|
||||
"shareWith": "Public",
|
||||
"dataSets": [
|
||||
{
|
||||
"codeName": "Multi-Period-Market",
|
||||
"type": "Market Files",
|
||||
"validPeriods": [ "24-hs", "12-hs", "08-hs", "06-hs", "04-hs", "03-hs", "02-hs", "01-hs" ],
|
||||
"filePath": "Masters/Candles-Volumes.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Volumes/Multi-Period-Market/@Period",
|
||||
"fileName": "@AssetA_@AssetB.json"
|
||||
},
|
||||
{
|
||||
"codeName": "Multi-Period-Daily",
|
||||
"type": "Daily Files",
|
||||
"validPeriods": [ "45-min", "40-min", "30-min", "20-min", "15-min", "10-min", "05-min", "04-min", "03-min", "02-min", "01-min" ],
|
||||
"filePath": "Masters/Candles-Volumes.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Volumes/Multi-Period-Daily/@Period/@Year/@Month/@Day",
|
||||
"fileName": "@AssetA_@AssetB.json",
|
||||
"dataRange": {
|
||||
"filePath": "Masters/Candles-Volumes.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Volumes/Multi-Period-Daily",
|
||||
"fileName": "Data.Range.@AssetA_@AssetB.json"
|
||||
}
|
||||
}
|
||||
],
|
||||
"exchangeList": [
|
||||
{
|
||||
"name": "Poloniex"
|
||||
},
|
||||
{
|
||||
"name": "Coss"
|
||||
}
|
||||
],
|
||||
"plotter": {
|
||||
"dataMine": "Masters",
|
||||
"codeName": "PlottersCandlesVolumes",
|
||||
"moduleName": "Volumes"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
let thisObject = {
|
||||
|
||||
};
|
||||
|
||||
return thisObject;
|
||||
};
|
||||
@@ -1,501 +0,0 @@
|
||||
|
||||
exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_STORAGE, STATUS_REPORT, EXCHANGE_API) {
|
||||
|
||||
const FULL_LOG = true;
|
||||
const LOG_FILE_CONTENT = false;
|
||||
const GMT_SECONDS = ':00.000 GMT+0000';
|
||||
const GMT_MILI_SECONDS = '.000 GMT+0000';
|
||||
const MODULE_NAME = "User Bot";
|
||||
const TRADES_FOLDER_NAME = "Trades";
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
start: start
|
||||
};
|
||||
|
||||
let utilities = UTILITIES.newCloudUtilities(bot, logger)
|
||||
let fileStorage = FILE_STORAGE.newFileStorage(logger);
|
||||
let statusDependencies
|
||||
|
||||
const ONE_MINUTE = 60000
|
||||
const MAX_TRADES_PER_EXECUTION = 100000
|
||||
const symbol = bot.market.baseAsset + '/' + bot.market.quotedAsset
|
||||
const ccxt = require('ccxt')
|
||||
|
||||
let allTrades = []
|
||||
let thisReport;
|
||||
let since
|
||||
let initialProcessTimestamp
|
||||
let beginingOfMarket
|
||||
let lastFileSaved
|
||||
let exchangeId
|
||||
let options = {}
|
||||
let fetchType = "by Time"
|
||||
let lastId
|
||||
let firstId
|
||||
let rateLimit
|
||||
let exchange
|
||||
let uiStartDate = new Date(bot.uiStartDate)
|
||||
|
||||
const limit = 1000
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
try {
|
||||
|
||||
logger.fileName = MODULE_NAME;
|
||||
logger.initialize();
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
|
||||
exchangeId = bot.exchange.toLowerCase()
|
||||
|
||||
/* Applying the parameters defined by the user at the Exchange node */
|
||||
if (bot.exchangeNode.config.API !== undefined) {
|
||||
for (let i = 0; i < bot.exchangeNode.config.API.length; i++) {
|
||||
if (bot.exchangeNode.config.API[i].method === 'fetchTrades') {
|
||||
if (bot.exchangeNode.config.API[i].class !== undefined) {
|
||||
exchangeId = bot.exchangeNode.config.API[i].class
|
||||
}
|
||||
if (bot.exchangeNode.config.API[i].fetchType !== undefined) {
|
||||
fetchType = bot.exchangeNode.config.API[i].fetchType
|
||||
}
|
||||
if (bot.exchangeNode.config.API[i].fetchTradesMethod !== undefined) {
|
||||
options = {
|
||||
'fetchTradesMethod': bot.exchangeNode.config.API[i].fetchTradesMethod
|
||||
}
|
||||
}
|
||||
if (bot.exchangeNode.config.API[i].firstId !== undefined) {
|
||||
firstId = bot.exchangeNode.config.API[i].firstId
|
||||
}
|
||||
if (bot.exchangeNode.config.API[i].rateLimit !== undefined) {
|
||||
rateLimit = bot.exchangeNode.config.API[i].rateLimit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let key = process.env.KEY
|
||||
let secret = process.env.SECRET
|
||||
|
||||
if (key === "undefined") { key = undefined }
|
||||
if (secret === "undefined") { secret = undefined }
|
||||
|
||||
|
||||
const exchangeClass = ccxt[exchangeId]
|
||||
const exchangeConstructorParams = {
|
||||
'apiKey': key,
|
||||
'secret': secret,
|
||||
'timeout': 30000,
|
||||
'enableRateLimit': true,
|
||||
verbose: false,
|
||||
options: options
|
||||
}
|
||||
if (rateLimit !== undefined) {
|
||||
exchangeConstructorParams.rateLimit = rateLimit
|
||||
}
|
||||
|
||||
exchange = new exchangeClass(exchangeConstructorParams)
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function start(callBackFunction) {
|
||||
try {
|
||||
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return
|
||||
}
|
||||
|
||||
let abort = false
|
||||
begin()
|
||||
|
||||
async function begin() {
|
||||
|
||||
getContextVariables()
|
||||
if (abort === true) { return }
|
||||
await getFirstId()
|
||||
await getTrades()
|
||||
if (abort === true) { return}
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return
|
||||
}
|
||||
await saveTrades()
|
||||
}
|
||||
|
||||
function getContextVariables() {
|
||||
|
||||
try {
|
||||
let reportKey;
|
||||
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-Trades"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
if (statusDependencies.statusReports.get(reportKey).status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
if (thisReport.file.beginingOfMarket !== undefined) { // This means this is not the first time this process run.
|
||||
beginingOfMarket = new Date(thisReport.file.beginingOfMarket.year + "-" + thisReport.file.beginingOfMarket.month + "-" + thisReport.file.beginingOfMarket.days + " " + thisReport.file.beginingOfMarket.hours + ":" + thisReport.file.beginingOfMarket.minutes + GMT_SECONDS);
|
||||
lastFileSaved = new Date(thisReport.file.lastFileSaved.year + "-" + thisReport.file.lastFileSaved.month + "-" + thisReport.file.lastFileSaved.days + " " + thisReport.file.lastFileSaved.hours + ":" + thisReport.file.lastFileSaved.minutes + GMT_SECONDS);
|
||||
lastId = thisReport.file.lastId
|
||||
} else { // This means this is the first time this process run.
|
||||
beginingOfMarket = new Date(uiStartDate.valueOf())
|
||||
}
|
||||
|
||||
defineSince()
|
||||
function defineSince() {
|
||||
if (thisReport.file.uiStartDate === undefined) {
|
||||
thisReport.file.uiStartDate = uiStartDate
|
||||
} else {
|
||||
thisReport.file.uiStartDate = new Date(thisReport.file.uiStartDate)
|
||||
}
|
||||
|
||||
if (uiStartDate.valueOf() !== thisReport.file.uiStartDate.valueOf()) {
|
||||
since = uiStartDate.valueOf()
|
||||
initialProcessTimestamp = since
|
||||
beginingOfMarket = new Date(uiStartDate.valueOf())
|
||||
} else {
|
||||
if (lastFileSaved !== undefined) {
|
||||
since = lastFileSaved.valueOf()
|
||||
initialProcessTimestamp = lastFileSaved.valueOf()
|
||||
} else {
|
||||
since = uiStartDate.valueOf()
|
||||
initialProcessTimestamp = uiStartDate.valueOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.stack);
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot Status Dependencies. ");
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
|
||||
}
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
abort = true
|
||||
}
|
||||
}
|
||||
|
||||
async function getFirstId() {
|
||||
try {
|
||||
/* We need the first id only when we are going to fetch trades based on id and it is the first time the process runs*/
|
||||
if (fetchType !== "by Id") { return }
|
||||
if (lastId !== undefined) { return }
|
||||
|
||||
const limit = 1
|
||||
const exchangeClass = ccxt[exchangeId]
|
||||
const exchange = new exchangeClass({
|
||||
'timeout': 30000,
|
||||
'enableRateLimit': true,
|
||||
verbose: false
|
||||
})
|
||||
|
||||
const trades = await exchange.fetchTrades(symbol, since, limit, undefined)
|
||||
|
||||
let lastRecord = trades[trades.length - 1]
|
||||
lastId = lastRecord.info[firstId]
|
||||
} catch (err) {
|
||||
/* If something fails trying to get an id close to since, we just will continue without an id.*/
|
||||
}
|
||||
}
|
||||
|
||||
async function getTrades() {
|
||||
|
||||
try {
|
||||
let lastTradeKey = ''
|
||||
let params = undefined
|
||||
let previousSince
|
||||
|
||||
while (true) {
|
||||
|
||||
/* Reporting we are doing well */
|
||||
let processingDate = new Date(since)
|
||||
processingDate = processingDate.getUTCFullYear() + '-' + utilities.pad(processingDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(processingDate.getUTCDate(), 2);
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getTrades -> Fetching Trades @ " + processingDate + "-> exchange = " + bot.exchange + " -> symbol = " + symbol + " -> since = " + since + " -> limit = " + limit ) }
|
||||
bot.processHeartBeat("Fetching " + allTrades.length.toFixed(0) + " trades from " + bot.exchange + " " + symbol + " @ " + processingDate) // tell the world we are alive and doing well
|
||||
|
||||
if (fetchType === "by Id") {
|
||||
params = {
|
||||
'fromId': lastId
|
||||
}
|
||||
since = undefined
|
||||
}
|
||||
|
||||
/* Fetching the trades from the exchange.*/
|
||||
const trades = await exchange.fetchTrades(symbol, since, limit, params)
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getTrades -> Trades Fetched = " + trades.length) }
|
||||
if (trades.length > 0) {
|
||||
let beginDate = new Date(trades[0].timestamp)
|
||||
let endDate = new Date(trades[trades.length - 1].timestamp)
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getTrades -> Trades Fetched From " + beginDate) }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getTrades -> Trades Fetched to " + endDate) }
|
||||
}
|
||||
|
||||
if (trades.length > 1) {
|
||||
previousSince = since
|
||||
since = trades[trades.length - 1]['timestamp']
|
||||
if (since === previousSince) {
|
||||
since++ // this prevents requesting in a loop trades with the same timestamp, that can happen when all the records fetched comes with exactly the same timestamp.
|
||||
}
|
||||
|
||||
lastId = trades[trades.length - 1]['id']
|
||||
|
||||
for (let i = 0; i < trades.length; i++) {
|
||||
let trade = trades[i]
|
||||
let tradeKey = trade.id + '-' + trade.timestamp + '-' + trade.side + '-' + trade.price.toFixed(16) + '-' + trade.amount.toFixed(16)
|
||||
if (tradeKey !== lastTradeKey) {
|
||||
allTrades.push([trade.timestamp, trade.side, trade.price, trade.amount, trade.id])
|
||||
}
|
||||
lastTradeKey = tradeKey
|
||||
}
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getTrades -> Fetching Trades @ " + processingDate + "-> exchange = " + bot.exchange + " -> symbol = " + symbol + " -> since = " + since + " -> limit = " + limit) }
|
||||
bot.processHeartBeat("Fetching " + allTrades.length.toFixed(0) + " trades from " + bot.exchange + " " + symbol + " @ " + processingDate) // tell the world we are alive and doing well
|
||||
|
||||
}
|
||||
|
||||
if (
|
||||
trades.length < limit - 1 ||
|
||||
global.STOP_TASK_GRACEFULLY === true ||
|
||||
allTrades.length >= MAX_TRADES_PER_EXECUTION
|
||||
) {
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getTrades -> Retrying Later -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
abort = true
|
||||
}
|
||||
}
|
||||
|
||||
async function saveTrades() {
|
||||
|
||||
try {
|
||||
|
||||
let fileContent = '['
|
||||
let previousRecordMinute = Math.trunc((initialProcessTimestamp - ONE_MINUTE) / ONE_MINUTE)
|
||||
let currentRecordMinute
|
||||
let needSeparator = false
|
||||
let error
|
||||
let separator
|
||||
let heartBeatCounter = 0
|
||||
|
||||
let i = -1
|
||||
lastId = undefined
|
||||
controlLoop()
|
||||
|
||||
function loop() {
|
||||
|
||||
let filesToCreate = 0
|
||||
let filesCreated = 0
|
||||
|
||||
let record = allTrades[i]
|
||||
let trade = {
|
||||
timestamp: record[0],
|
||||
side: record[1],
|
||||
price: record[2],
|
||||
amount: record[3]
|
||||
}
|
||||
|
||||
if (lastId === undefined) {
|
||||
lastId = record[4]
|
||||
}
|
||||
|
||||
let processingDate = new Date(trade.timestamp)
|
||||
processingDate = processingDate.getUTCFullYear() + '-' + utilities.pad(processingDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(processingDate.getUTCDate(), 2);
|
||||
|
||||
/* Reporting we are doing well */
|
||||
heartBeatCounter--
|
||||
if (heartBeatCounter <= 0) {
|
||||
heartBeatCounter = 1000
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> saveTrades -> Saving Trades @ " + processingDate + " -> i = " + i + " -> total = " + allTrades.length) }
|
||||
bot.processHeartBeat("Saving " + i.toFixed(0) + " trades from " + bot.exchange + " " + symbol + " @ " + processingDate) // tell the world we are alive and doing well
|
||||
}
|
||||
|
||||
/* Saving the trades in Files*/
|
||||
currentRecordMinute = Math.trunc(trade.timestamp / ONE_MINUTE)
|
||||
|
||||
if (
|
||||
currentRecordMinute !== previousRecordMinute
|
||||
) {
|
||||
/* There are no more trades at this minute or it is the last trade, so we save the file.*/
|
||||
saveFile(previousRecordMinute)
|
||||
lastId = undefined
|
||||
}
|
||||
|
||||
if (needSeparator === false) {
|
||||
needSeparator = true;
|
||||
separator = '';
|
||||
} else {
|
||||
separator = ',';
|
||||
}
|
||||
|
||||
/* Add the trade to the file content.*/
|
||||
fileContent = fileContent + separator + '[' + trade.timestamp + ',"' + trade.side + '",' + trade.price + ',' + trade.amount + ']';
|
||||
|
||||
if (i === allTrades.length - 1) {
|
||||
/* This is the last trade, so we save the file.*/
|
||||
saveFile(currentRecordMinute)
|
||||
/* It might happen that there are several minutes after the last trade without trades. We need to record empty files for them.*/
|
||||
if (allTrades.length < MAX_TRADES_PER_EXECUTION) {
|
||||
let currentTimeMinute = Math.trunc((new Date()).valueOf() / ONE_MINUTE)
|
||||
if (currentTimeMinute - currentRecordMinute > 1) {
|
||||
createMissingEmptyFiles(currentRecordMinute, currentTimeMinute)
|
||||
}
|
||||
}
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> saveTrades -> Saving Trades @ " + processingDate + " -> i = " + i + " -> total = " + allTrades.length) }
|
||||
bot.processHeartBeat("Saving " + i.toFixed(0) + " trades from " + bot.exchange + " " + symbol + " @ " + processingDate) // tell the world we are alive and doing well
|
||||
|
||||
return
|
||||
}
|
||||
previousRecordMinute = currentRecordMinute
|
||||
if (error) {
|
||||
callBackFunction(error);
|
||||
return;
|
||||
}
|
||||
if (filesToCreate === 0) {
|
||||
controlLoop()
|
||||
}
|
||||
function saveFile(minute) {
|
||||
fileContent = fileContent + ']'
|
||||
if (currentRecordMinute - previousRecordMinute > 1) {
|
||||
createMissingEmptyFiles(previousRecordMinute, currentRecordMinute)
|
||||
}
|
||||
let fileName = 'Data.json'
|
||||
if (previousRecordMinute >= initialProcessTimestamp / ONE_MINUTE) {
|
||||
filesToCreate++
|
||||
fileStorage.createTextFile(getFilePath(minute * ONE_MINUTE) + '/' + fileName, fileContent + '\n', onFileCreated);
|
||||
}
|
||||
fileContent = '['
|
||||
needSeparator = false
|
||||
|
||||
}
|
||||
function createMissingEmptyFiles(begin, end) {
|
||||
|
||||
/*
|
||||
If this range is too wide, we will consider this means that the begin is before the begining of this market at this exchange.
|
||||
In that case we will change the begin and the beginingOfMarket
|
||||
*/
|
||||
|
||||
if ((end - begin) / 60 / 24 > 7) {
|
||||
begin = end
|
||||
beginingOfMarket = new Date(end * ONE_MINUTE)
|
||||
}
|
||||
|
||||
for (let j = begin + 1; j < end; j++) {
|
||||
let fileName = 'Data.json'
|
||||
filesToCreate++
|
||||
fileStorage.createTextFile(getFilePath(j * ONE_MINUTE) + '/' + fileName, "[]" + '\n', onFileCreated);
|
||||
|
||||
}
|
||||
}
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> tradesReadyToBeSaved -> onFileBCreated -> err = " + JSON.stringify(err));
|
||||
error = err // This allows the loop to be breaked.
|
||||
return;
|
||||
}
|
||||
filesCreated++
|
||||
lastFileSaved = new Date((currentRecordMinute * ONE_MINUTE))
|
||||
if (filesCreated === filesToCreate) {
|
||||
controlLoop()
|
||||
}
|
||||
}
|
||||
function getFilePath(timestamp) {
|
||||
let datetime = new Date(timestamp)
|
||||
let dateForPath = datetime.getUTCFullYear() + '/' +
|
||||
utilities.pad(datetime.getUTCMonth() + 1, 2) + '/' +
|
||||
utilities.pad(datetime.getUTCDate(), 2) + '/' +
|
||||
utilities.pad(datetime.getUTCHours(), 2) + '/' +
|
||||
utilities.pad(datetime.getUTCMinutes(), 2)
|
||||
let filePath = bot.filePathRoot + "/Output/" + TRADES_FOLDER_NAME + '/' + dateForPath;
|
||||
return filePath
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
function controlLoop() {
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return
|
||||
}
|
||||
|
||||
i++
|
||||
if (i < allTrades.length) {
|
||||
setImmediate(loop)
|
||||
} else {
|
||||
writeStatusReport()
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> saveTrades -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
abort = true
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport() {
|
||||
try {
|
||||
if (lastFileSaved === undefined) {return}
|
||||
thisReport.file = {
|
||||
lastFileSaved: {
|
||||
year: lastFileSaved.getUTCFullYear(),
|
||||
month: (lastFileSaved.getUTCMonth() + 1),
|
||||
days: lastFileSaved.getUTCDate(),
|
||||
hours: lastFileSaved.getUTCHours(),
|
||||
minutes: lastFileSaved.getUTCMinutes()
|
||||
},
|
||||
beginingOfMarket: {
|
||||
year: beginingOfMarket.getUTCFullYear(),
|
||||
month: (beginingOfMarket.getUTCMonth() + 1),
|
||||
days: beginingOfMarket.getUTCDate(),
|
||||
hours: beginingOfMarket.getUTCHours(),
|
||||
minutes: beginingOfMarket.getUTCMinutes()
|
||||
},
|
||||
uiStartDate: uiStartDate.toUTCString()
|
||||
};
|
||||
|
||||
if (fetchType === "by Id") {
|
||||
thisReport.file.lastId = lastId
|
||||
}
|
||||
|
||||
thisReport.save(onSaved);
|
||||
|
||||
function onSaved(err) {
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> onSaved -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "AACharly",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "AACharly",
|
||||
"version": "1.0.0",
|
||||
"description": "Processes that get the trades from Poloniex.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Luis-Fernando-Molina",
|
||||
"license": "ISC",
|
||||
"dependencies": {}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
{
|
||||
"displayName": "Exchange Raw Data",
|
||||
"codeName": "Exchange-Raw-Data",
|
||||
"type": "Sensor Bot",
|
||||
"dataMine": "Masters",
|
||||
"profilePicture": "Exchange Raw Data.png",
|
||||
"processes": [
|
||||
{
|
||||
"name": "Live-Trades",
|
||||
"description": "Retrieves the trades done at the current and the previous minute and saves them at the storage account.",
|
||||
"startMode": {
|
||||
"allMonths": {
|
||||
"run": "false",
|
||||
"minYear": "",
|
||||
"maxYear": ""
|
||||
},
|
||||
"oneMonth": {
|
||||
"run": "false",
|
||||
"year": "",
|
||||
"month": ""
|
||||
},
|
||||
"noTime": {
|
||||
"run": "false"
|
||||
},
|
||||
"fixedInterval": {
|
||||
"run": "true",
|
||||
"interval": 60000
|
||||
}
|
||||
},
|
||||
"deadWaitTime": 0,
|
||||
"normalWaitTime": 60000,
|
||||
"retryWaitTime": 10000,
|
||||
"sleepWaitTime": 3600000,
|
||||
"comaWaitTime": 86400000,
|
||||
"statusDependencies": [
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Live-Trades"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Historic-Trades",
|
||||
"description": "Retrieves and saves the historical trades in batches going backwards from the current time until reaching the begining of the market.",
|
||||
"startMode": {
|
||||
"allMonths": {
|
||||
"run": "false",
|
||||
"minYear": "2014",
|
||||
"maxYear": "2020"
|
||||
},
|
||||
"oneMonth": {
|
||||
"run": "true",
|
||||
"year": "2018",
|
||||
"month": "01"
|
||||
},
|
||||
"noTime": {
|
||||
"run": "false"
|
||||
},
|
||||
"fixedInterval": {
|
||||
"run": "false",
|
||||
"interval": 0
|
||||
}
|
||||
},
|
||||
"deadWaitTime": 0,
|
||||
"normalWaitTime": 60000,
|
||||
"retryWaitTime": 10000,
|
||||
"sleepWaitTime": 3600000,
|
||||
"comaWaitTime": 86400000,
|
||||
"statusDependencies": [
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Live-Trades"
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Historic-Trades"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Hole-Fixing",
|
||||
"description": "Scans the trades saved by the Live Trades and Historic Trades processes searching for missing records. Once a hole is found on the data set, it patches it by retrieving the missing records from the exchange.",
|
||||
"startMode": {
|
||||
"allMonths": {
|
||||
"run": "true",
|
||||
"minYear": "2019",
|
||||
"maxYear": "2019"
|
||||
},
|
||||
"oneMonth": {
|
||||
"run": "false",
|
||||
"year": "2019",
|
||||
"month": "10"
|
||||
},
|
||||
"noTime": {
|
||||
"run": "false"
|
||||
},
|
||||
"fixedInterval": {
|
||||
"run": "false",
|
||||
"interval": 0
|
||||
}
|
||||
},
|
||||
"deadWaitTime": 0,
|
||||
"normalWaitTime": 0,
|
||||
"retryWaitTime": 10000,
|
||||
"sleepWaitTime": 3600000,
|
||||
"comaWaitTime": 86400000,
|
||||
"statusDependencies": [
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Live-Trades",
|
||||
"waitUntilNextUpdate": true
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Historic-Trades"
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Hole-Fixing",
|
||||
"dataSetSection": "Month"
|
||||
},
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Exchange-Raw-Data",
|
||||
"process": "Hole-Fixing"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
|
||||
exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_STORAGE, STATUS_REPORT, EXCHANGE_API) {
|
||||
|
||||
const FULL_LOG = true;
|
||||
const LOG_FILE_CONTENT = false;
|
||||
const MODULE_NAME = "User Bot";
|
||||
const FOLDER_NAME = "External-Signals";
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
start: start
|
||||
};
|
||||
|
||||
let utilities = UTILITIES.newCloudUtilities(bot, logger)
|
||||
let fileStorage = FILE_STORAGE.newFileStorage(logger);
|
||||
let statusDependencies
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
try {
|
||||
|
||||
logger.fileName = MODULE_NAME;
|
||||
logger.initialize();
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function start(callBackFunction) {
|
||||
try {
|
||||
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return
|
||||
}
|
||||
|
||||
let fileContent
|
||||
|
||||
getContextVariables(saveMessages)
|
||||
|
||||
function getContextVariables(callBack) {
|
||||
|
||||
try {
|
||||
let reportKey;
|
||||
|
||||
reportKey = "Masters" + "-" + "Webhooks" + "-" + "Check-Webhook"
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
|
||||
if (statusDependencies.statusReports.get(reportKey).status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
if (thisReport.file.lasrRun !== undefined) {
|
||||
|
||||
let fileName = 'Data.json'
|
||||
let filePath = bot.filePathRoot + "/Output/" + FOLDER_NAME + "/" + 'Single-File'
|
||||
fileStorage.getTextFile(filePath + '/' + fileName, onFileReceived);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> onFileReceived -> Could read file. -> filePath = " + filePath + "/" + fileName);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
} else {
|
||||
|
||||
fileContent = text
|
||||
callBack()
|
||||
}
|
||||
}
|
||||
} else { // If there is no status report, we assume there is no previous file or that if there is we will override it.
|
||||
callBack()
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.stack);
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot Status Dependencies. ");
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
|
||||
}
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
abort = true
|
||||
}
|
||||
}
|
||||
|
||||
function saveMessages() {
|
||||
try {
|
||||
|
||||
let http = require('http');
|
||||
let url = 'http://' + process.env.WEB_SERVER_URL +
|
||||
':' + process.env.HTTP_INTERFACE_PORT +
|
||||
'/Webhook/Fetch-Messages/' +
|
||||
bot.exchange + "/" +
|
||||
bot.market.baseAsset + "-" + bot.market.quotedAsset
|
||||
|
||||
http.get(url, onResponse);
|
||||
|
||||
function onResponse(response) {
|
||||
|
||||
const chunks = []
|
||||
|
||||
response.on('data', onMessegesArrived)
|
||||
response.on('end', onEnd)
|
||||
|
||||
function onMessegesArrived(chunk) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
function onEnd() {
|
||||
let messages = Buffer.concat(chunks).toString('utf8')
|
||||
|
||||
if (fileContent !== undefined) {
|
||||
// we are going to append the curernt messages to the existing file.
|
||||
let fileContentArray = JSON.parse(fileContent)
|
||||
let messagesArray = JSON.parse(messages)
|
||||
|
||||
for (let i = 0; i < messagesArray.length; i++) {
|
||||
let message = messagesArray[i]
|
||||
fileContentArray.push(message)
|
||||
}
|
||||
|
||||
fileContent = JSON.stringify(fileContentArray)
|
||||
} else {
|
||||
// we are going to save the current messages.
|
||||
fileContent = messages
|
||||
}
|
||||
|
||||
let fileName = 'Data.json'
|
||||
let filePath = bot.filePathRoot + "/Output/" + FOLDER_NAME + "/" + 'Single-File'
|
||||
fileStorage.createTextFile(filePath + '/' + fileName, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> saveMessages -> onResponse -> onEnd -> onFileCreated -> Could not save file. -> filePath = " + filePath + "/" + fileName);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
} else {
|
||||
writeStatusReport()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> saveMessages -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
abort = true
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport() {
|
||||
try {
|
||||
|
||||
thisReport.file = {
|
||||
lasrRun: (new Date()).toISOString()
|
||||
};
|
||||
|
||||
thisReport.save(onSaved);
|
||||
|
||||
function onSaved(err) {
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> onSaved -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
let thisObject = {
|
||||
|
||||
};
|
||||
|
||||
return thisObject;
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "AACharly",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"name": "webhooks-sensor-bot",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "",
|
||||
"author": "Luis-Fernando-Molina",
|
||||
"license": "",
|
||||
"dependencies": {}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"displayName": "Webhooks",
|
||||
"codeName": "Webhooks",
|
||||
"type": "Sensor Bot",
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0,
|
||||
"patch": 0
|
||||
},
|
||||
"dataMine": "Masters",
|
||||
"processes": [
|
||||
{
|
||||
"name": "Check-Webhook",
|
||||
"description": "",
|
||||
"startMode": {
|
||||
"allMonths": {
|
||||
"run": "false",
|
||||
"minYear": "",
|
||||
"maxYear": ""
|
||||
},
|
||||
"oneMonth": {
|
||||
"run": "false",
|
||||
"year": "",
|
||||
"month": ""
|
||||
},
|
||||
"noTime": {
|
||||
"run": "false"
|
||||
},
|
||||
"fixedInterval": {
|
||||
"run": "true",
|
||||
"interval": 60000
|
||||
}
|
||||
},
|
||||
"deadWaitTime": 0,
|
||||
"normalWaitTime": 30000,
|
||||
"retryWaitTime": 10000,
|
||||
"sleepWaitTime": 3600000,
|
||||
"comaWaitTime": 86400000,
|
||||
"statusDependencies": [
|
||||
{
|
||||
"dataMine": "Masters",
|
||||
"bot": "Webhooks",
|
||||
"process": "Check-Webhook"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
const ERROR_LOG = true;
|
||||
const INTENSIVE_LOG = false;
|
||||
const logger = newWebDebugLog();
|
||||
logger.fileName = MODULE_NAME;
|
||||
|
||||
|
||||
let thisObject = {
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
const ERROR_LOG = true;
|
||||
const INTENSIVE_LOG = false;
|
||||
const logger = newWebDebugLog();
|
||||
logger.fileName = MODULE_NAME;
|
||||
|
||||
|
||||
let thisObject = {
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
const ERROR_LOG = true;
|
||||
const INTENSIVE_LOG = false;
|
||||
const logger = newWebDebugLog();
|
||||
logger.fileName = MODULE_NAME;
|
||||
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
const ERROR_LOG = true;
|
||||
const INTENSIVE_LOG = false;
|
||||
const logger = newWebDebugLog();
|
||||
logger.fileName = MODULE_NAME;
|
||||
|
||||
|
||||
let thisObject = {
|
||||
|
||||
|
||||
@@ -1,572 +0,0 @@
|
||||
function newSuperalgosFunctionLibraryCryptoEcosystemFunctions() {
|
||||
thisObject = {
|
||||
addMissingExchanges: addMissingExchanges,
|
||||
addMissingAssets: addMissingAssets,
|
||||
addMissingMarkets: addMissingMarkets,
|
||||
installMarket: installMarket,
|
||||
uninstallMarket: uninstallMarket
|
||||
}
|
||||
|
||||
return thisObject
|
||||
|
||||
function addMissingExchanges(node) {
|
||||
currentExchanges = new Map()
|
||||
let parent = node.payload.parentNode
|
||||
if (parent !== undefined) {
|
||||
for (let i = 0; i < parent.cryptoExchanges.length; i++) {
|
||||
let cryptoExchanges = parent.cryptoExchanges[i]
|
||||
for (let j = 0; j < cryptoExchanges.exchanges.length; j++) {
|
||||
let exchange = cryptoExchanges.exchanges[j]
|
||||
let codeName = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(exchange.payload, 'codeName')
|
||||
currentExchanges.set(codeName, exchange)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let params = {
|
||||
method: 'listExchanges',
|
||||
has: {
|
||||
fetchOHLCV: true,
|
||||
fetchMarkets: true
|
||||
}
|
||||
}
|
||||
|
||||
httpRequest(JSON.stringify(params), 'CCXT', onResponse)
|
||||
|
||||
function onResponse(err, data) {
|
||||
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
node.payload.uiObject.setErrorMessage('Failed to Fetch Assets from the Exchange')
|
||||
return
|
||||
}
|
||||
|
||||
let exchanges = JSON.parse(data)
|
||||
for (let i = 0; i < exchanges.length; i++) {
|
||||
let exchange = exchanges[i]
|
||||
let existingExchange = currentExchanges.get(exchange.id)
|
||||
if (existingExchange === undefined) {
|
||||
let newExchange = UI.projects.superalgos.functionLibraries.uiObjectsFromNodes.addUIObject(node, 'Crypto Exchange')
|
||||
newExchange.name = exchange.name
|
||||
newExchange.config = '{ \n\"codeName\": \"' + exchange.id + '\"\n}'
|
||||
newExchange.payload.floatingObject.collapseToggle()
|
||||
newExchange.exchangeAssets.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
|
||||
newExchange.exchangeMarkets.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
|
||||
newExchange.exchangeAccounts.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
|
||||
newExchange.exchangeAssets.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_050X
|
||||
newExchange.exchangeMarkets.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_100X
|
||||
newExchange.exchangeAccounts.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_025X
|
||||
newExchange.exchangeAssets.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
|
||||
newExchange.exchangeMarkets.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
|
||||
newExchange.exchangeAccounts.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addMissingAssets(node) {
|
||||
if (node.payload.parentNode === undefined) { return }
|
||||
|
||||
let currentAssets = new Map()
|
||||
for (let j = 0; j < node.assets.length; j++) {
|
||||
let asset = node.assets[j]
|
||||
let codeName = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(asset.payload, 'codeName')
|
||||
currentAssets.set(codeName, asset)
|
||||
}
|
||||
|
||||
let exchangeId = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload.parentNode.payload, 'codeName')
|
||||
|
||||
try {
|
||||
let params = {
|
||||
exchangeId: exchangeId,
|
||||
method: 'fetchMarkets'
|
||||
}
|
||||
httpRequest(JSON.stringify(params), 'CCXT', onResponse)
|
||||
|
||||
function onResponse(err, data) {
|
||||
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
node.payload.uiObject.setErrorMessage('Failed to Fetch Assets from the Exchange')
|
||||
return
|
||||
}
|
||||
let queryParams = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload, 'addMissingAssetsFilter')
|
||||
|
||||
let markets = JSON.parse(data)
|
||||
|
||||
let totalAdded = 0
|
||||
for (let i = 0; i < markets.length; i++) {
|
||||
let market = markets[i]
|
||||
|
||||
if (queryParams !== undefined) {
|
||||
if (queryParams.baseAsset !== undefined) {
|
||||
if (market.base.indexOf(queryParams.baseAsset) < 0) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (queryParams.quotedAsset !== undefined) {
|
||||
if (market.quote.indexOf(queryParams.quotedAsset) < 0) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentAssets.get(market.base) === undefined) {
|
||||
addAsset(market.base)
|
||||
totalAdded++
|
||||
currentAssets.set(market.base, market.base)
|
||||
}
|
||||
if (currentAssets.get(market.quote) === undefined) {
|
||||
addAsset(market.quote)
|
||||
totalAdded++
|
||||
currentAssets.set(market.quote, market.quote)
|
||||
}
|
||||
|
||||
function addAsset(name) {
|
||||
let newAsseet = UI.projects.superalgos.functionLibraries.uiObjectsFromNodes.addUIObject(node, 'Asset')
|
||||
newAsseet.name = name
|
||||
newAsseet.config = '{ \n\"codeName\": \"' + name + '\"\n}'
|
||||
}
|
||||
}
|
||||
node.payload.uiObject.setInfoMessage(node.payload.parentNode.name + ' supports ' + markets.length + ' markets. Applying the filters at this node config ' + node.config + ' this process added ' + totalAdded + ' assets.', 4)
|
||||
|
||||
}
|
||||
} catch (err) {
|
||||
node.payload.uiObject.setErrorMessage('Failed to Fetch Assets from the Exchange')
|
||||
console.log(err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
function addMissingMarkets(node) {
|
||||
if (node.payload.parentNode === undefined) { return }
|
||||
if (node.payload.parentNode.exchangeAssets === undefined) { return }
|
||||
if (node.payload.parentNode.payload.parentNode === undefined) { return }
|
||||
if (node.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { return }
|
||||
|
||||
let currentAssets = new Map()
|
||||
let exchangeAssets = node.payload.parentNode.exchangeAssets
|
||||
for (let j = 0; j < exchangeAssets.assets.length; j++) {
|
||||
let asset = exchangeAssets.assets[j]
|
||||
let codeName = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(asset.payload, 'codeName')
|
||||
currentAssets.set(codeName, asset)
|
||||
}
|
||||
|
||||
let currentMarkets = new Map()
|
||||
let exchangeMarkets = node
|
||||
for (let j = 0; j < exchangeMarkets.markets.length; j++) {
|
||||
let asset = exchangeMarkets.markets[j]
|
||||
let codeName = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(asset.payload, 'codeName')
|
||||
currentMarkets.set(codeName, asset)
|
||||
}
|
||||
|
||||
let exchangeId = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload.parentNode.payload, 'codeName')
|
||||
|
||||
try {
|
||||
let params = {
|
||||
exchangeId: exchangeId,
|
||||
method: 'fetchMarkets'
|
||||
}
|
||||
httpRequest(JSON.stringify(params), 'CCXT', onResponse)
|
||||
|
||||
function onResponse(err, data) {
|
||||
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
node.payload.uiObject.setErrorMessage('Failed to Fetch Assets from the Exchange')
|
||||
return
|
||||
}
|
||||
|
||||
let markets = JSON.parse(data)
|
||||
for (let i = 0; i < markets.length; i++) {
|
||||
let market = markets[i]
|
||||
let baseAsset = currentAssets.get(market.base)
|
||||
let quotedAsset = currentAssets.get(market.quote)
|
||||
|
||||
if (baseAsset === undefined) {
|
||||
continue
|
||||
}
|
||||
if (quotedAsset === undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (currentMarkets.get(market.symbol) === undefined) {
|
||||
addMarket(market.symbol, baseAsset, quotedAsset)
|
||||
}
|
||||
|
||||
function addMarket(name, baseAsset, quotedAsset) {
|
||||
let newMarket = UI.projects.superalgos.functionLibraries.uiObjectsFromNodes.addUIObject(node, 'Market')
|
||||
newMarket.name = name
|
||||
newMarket.config = '{ \n\"codeName\": \"' + name + '\"\n}'
|
||||
newMarket.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
|
||||
newMarket.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_100X
|
||||
newMarket.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
|
||||
newMarket.baseAsset.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_45
|
||||
newMarket.quotedAsset.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_45
|
||||
newMarket.baseAsset.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_100X
|
||||
newMarket.quotedAsset.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_100X
|
||||
newMarket.baseAsset.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
|
||||
newMarket.quotedAsset.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
|
||||
newMarket.baseAsset.payload.referenceParent = baseAsset
|
||||
newMarket.quotedAsset.payload.referenceParent = quotedAsset
|
||||
|
||||
currentMarkets.set(name, newMarket)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
node.payload.uiObject.setErrorMessage('Failed to Fetch Assets from the Exchange')
|
||||
console.log(err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
function installMarket(
|
||||
node,
|
||||
rootNodes
|
||||
) {
|
||||
|
||||
let market = node
|
||||
let cryptoExchange = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(node, 'Crypto Exchange', undefined, true, false, true, false)
|
||||
if (cryptoExchange === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Market must be a descendant of a Crypto Exchange')
|
||||
return
|
||||
}
|
||||
node.payload.uiObject.setInfoMessage('This market is being installed. This might take a minute or two. Please hold on while we connect all the dots for you. ')
|
||||
|
||||
setTimeout(installMarketProcedure, 500)
|
||||
|
||||
function installMarketProcedure() {
|
||||
let dashboardsArray = []
|
||||
|
||||
for (let i = 0; i < rootNodes.length; i++) {
|
||||
let rootNode = rootNodes[i]
|
||||
if (rootNode.type === 'Network') {
|
||||
installInNetwork(rootNode)
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < rootNodes.length; i++) {
|
||||
let rootNode = rootNodes[i]
|
||||
if (rootNode.type === 'Charting Space') {
|
||||
installInChartingSpace(rootNode)
|
||||
}
|
||||
}
|
||||
|
||||
node.payload.uiObject.setInfoMessage('Market installation is complete.')
|
||||
|
||||
function installInNetwork(network) {
|
||||
|
||||
for (let j = 0; j < network.networkNodes.length; j++) {
|
||||
let networkNode = network.networkNodes[j]
|
||||
installInNetworkNode(networkNode)
|
||||
}
|
||||
|
||||
function installInNetworkNode(networkNode) {
|
||||
|
||||
let tradingSessionsCreatedArray = []
|
||||
let learningSessionsCreatedArray = []
|
||||
|
||||
installDataMiningTasks()
|
||||
installLearningMiningTasks()
|
||||
isntallTradingMiningTasks()
|
||||
|
||||
installDataMinesData()
|
||||
installLearningMinesData()
|
||||
installTradingMineData()
|
||||
|
||||
function installDataMiningTasks() {
|
||||
/*
|
||||
Here we complete the missing stuff at Data Mining
|
||||
*/
|
||||
let dataMining = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, 'Data Mining', node, true)
|
||||
if (dataMining === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Data Mining node not found at Network Node ' + networkNode.name)
|
||||
return
|
||||
}
|
||||
|
||||
let exchangeDataTasks = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(dataMining, 'Exchange Data Tasks', cryptoExchange)
|
||||
exchangeDataTasks.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
|
||||
let marketDataTask = UI.projects.superalgos.utilities.children.findAndRecreateChildWithReference(exchangeDataTasks, 'Market Data Tasks', market, rootNodes)
|
||||
|
||||
UI.projects.superalgos.utilities.menu.menuClick(marketDataTask, 'Add Missing Data Mine Tasks', true)
|
||||
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(marketDataTask.dataMineTasks, 'Add All Tasks', true)
|
||||
}
|
||||
|
||||
function installLearningMiningTasks() {
|
||||
/*
|
||||
Here we complete the missing stuff at Learning Mining
|
||||
*/
|
||||
let learningMining = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, 'Learning Mining', node, true)
|
||||
if (learningMining === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Learning Mining node not found at Network Node ' + networkNode.name)
|
||||
return
|
||||
}
|
||||
|
||||
let exchangeLearningTasks = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(learningMining, 'Exchange Learning Tasks', cryptoExchange)
|
||||
exchangeLearningTasks.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
|
||||
let marketLearningTask = UI.projects.superalgos.utilities.children.findAndRecreateChildWithReference(exchangeLearningTasks, 'Market Learning Tasks', market, rootNodes)
|
||||
|
||||
UI.projects.superalgos.utilities.menu.menuClick(marketLearningTask, 'Add Missing Learning Mine Tasks', true)
|
||||
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(marketLearningTask.learningMineTasks, 'Add All Tasks', true)
|
||||
|
||||
/* This will be needed at the charting space, for creating Dashboards */
|
||||
let learningSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(marketLearningTask, 'Learning Session')
|
||||
learningSessionsCreatedArray = learningSessionsCreatedArray.concat(learningSessionsArray)
|
||||
}
|
||||
|
||||
function isntallTradingMiningTasks() {
|
||||
/*
|
||||
Next we complete the missing stuff at Testing Environment
|
||||
*/
|
||||
installEnvironment('Testing Environment')
|
||||
/*
|
||||
Next we complete the missing stuff at Production Environment
|
||||
*/
|
||||
installEnvironment('Production Environment')
|
||||
|
||||
function installEnvironment(environment) {
|
||||
/*
|
||||
Now we install the environmnet at the current Network Node
|
||||
*/
|
||||
let environmentFound = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, environment, node, true)
|
||||
if (environmentFound === undefined) {
|
||||
node.payload.uiObject.setErrorMessage(environment + ' node not found at Network Node ' + networkNode.name)
|
||||
return
|
||||
}
|
||||
|
||||
let exchangeTradingTasks = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(environmentFound, 'Exchange Trading Tasks', cryptoExchange)
|
||||
exchangeTradingTasks.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
|
||||
let marketTradingTask = UI.projects.superalgos.utilities.children.findAndRecreateChildWithReference(exchangeTradingTasks, 'Market Trading Tasks', market, rootNodes)
|
||||
|
||||
UI.projects.superalgos.utilities.menu.menuClick(marketTradingTask, 'Add Missing Trading Mine Tasks', true)
|
||||
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(marketTradingTask.tradingMineTasks, 'Add All Tasks', true)
|
||||
|
||||
/* This will be needed at the charting space, for creating Dashboards */
|
||||
let backtestingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(marketTradingTask, 'Backtesting Session')
|
||||
let liveTradingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(marketTradingTask, 'Live Trading Session')
|
||||
let paperTradingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(marketTradingTask, 'Paper Trading Session')
|
||||
let forwardSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(marketTradingTask, 'Forward Testing Session')
|
||||
let allSessionsArray = backtestingSessionsArray
|
||||
.concat(liveTradingSessionsArray)
|
||||
.concat(paperTradingSessionsArray)
|
||||
.concat(forwardSessionsArray)
|
||||
tradingSessionsCreatedArray = tradingSessionsCreatedArray.concat(allSessionsArray)
|
||||
|
||||
dashboardsArray.push({ environmentNode: environmentFound, networkNode: networkNode, sessionsArray: allSessionsArray })
|
||||
}
|
||||
}
|
||||
|
||||
function installDataMinesData() {
|
||||
/*
|
||||
Here we complete the missing stuff at Data Mines Data
|
||||
*/
|
||||
let dataMinesData = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, 'Data Mines Data', node, true)
|
||||
if (dataMinesData === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Data Mines Data node not found at Network Node ' + networkNode.name)
|
||||
return
|
||||
}
|
||||
|
||||
let exchangeDataProducts = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(dataMinesData, 'Exchange Data Products', cryptoExchange)
|
||||
exchangeDataProducts.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
|
||||
let marketDataProducts = UI.projects.superalgos.utilities.children.findAndRecreateChildWithReference(exchangeDataProducts, 'Market Data Products', market, rootNodes)
|
||||
marketDataProducts.payload.floatingObject.collapseToggle()
|
||||
|
||||
UI.projects.superalgos.utilities.menu.menuClick(marketDataProducts, 'Add All Data Mine Products', true)
|
||||
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(marketDataProducts.dataMineProducts, 'Add All Data Products', true)
|
||||
}
|
||||
|
||||
function installLearningMinesData() {
|
||||
/*
|
||||
Here we complete the missing stuff at Learning Mines Data
|
||||
*/
|
||||
let learningMinesData = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, 'Learning Mines Data', node, true)
|
||||
if (learningMinesData === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Learning Mines Data node not found at Network Node ' + networkNode.name)
|
||||
return
|
||||
}
|
||||
|
||||
let exchangeLearningProducts = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(learningMinesData, 'Exchange Learning Products', cryptoExchange)
|
||||
exchangeLearningProducts.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
|
||||
let marketLearningProducts = UI.projects.superalgos.utilities.children.findAndRecreateChildWithReference(exchangeLearningProducts, 'Market Learning Products', market, rootNodes)
|
||||
marketLearningProducts.payload.floatingObject.collapseToggle()
|
||||
/*
|
||||
Create the new session references.
|
||||
*/
|
||||
for (let i = 0; i < learningSessionsCreatedArray.length; i++) {
|
||||
let session = learningSessionsCreatedArray[i]
|
||||
if (UI.projects.superalgos.utilities.children.isMissingChildren(marketLearningProducts, session, true) === true) {
|
||||
UI.projects.superalgos.functionLibraries.dataStorageFunctions.createSessionReference(marketLearningProducts, session, 'Learning Session Reference')
|
||||
}
|
||||
}
|
||||
/*
|
||||
Create everything inside the session references.
|
||||
*/
|
||||
for (let j = 0; j < marketLearningProducts.learningSessionReferences.length; j++) {
|
||||
let sessionReference = marketLearningProducts.learningSessionReferences[j]
|
||||
UI.projects.superalgos.utilities.menu.menuClick(sessionReference, 'Add All Learning Mine Products', true)
|
||||
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(sessionReference.learningMineProducts, 'Add All Data Products', true)
|
||||
sessionReference.payload.floatingObject.collapseToggle()
|
||||
}
|
||||
}
|
||||
|
||||
function installTradingMineData() {
|
||||
/*
|
||||
Finally we complete the missing stuff at Trading Mines Data
|
||||
*/
|
||||
let tradingMinesData = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, 'Trading Mines Data', node, true)
|
||||
if (tradingMinesData === undefined) {
|
||||
node.payload.uiObject.setErrorMessage('Trading Mines Data node not found at Network Node ' + networkNode.name)
|
||||
return
|
||||
}
|
||||
|
||||
let exchangeTradingProducts = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(tradingMinesData, 'Exchange Trading Products', cryptoExchange)
|
||||
exchangeTradingProducts.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
|
||||
let marketTradingProducts = UI.projects.superalgos.utilities.children.findAndRecreateChildWithReference(exchangeTradingProducts, 'Market Trading Products', market, rootNodes)
|
||||
marketTradingProducts.payload.floatingObject.collapseToggle()
|
||||
/*
|
||||
Create the new session references.
|
||||
*/
|
||||
for (let i = 0; i < tradingSessionsCreatedArray.length; i++) {
|
||||
let session = tradingSessionsCreatedArray[i]
|
||||
if (UI.projects.superalgos.utilities.children.isMissingChildren(marketTradingProducts, session, true) === true) {
|
||||
UI.projects.superalgos.functionLibraries.dataStorageFunctions.createSessionReference(marketTradingProducts, session, 'Trading Session Reference')
|
||||
}
|
||||
}
|
||||
/*
|
||||
Create everything inside the session references.
|
||||
*/
|
||||
for (let j = 0; j < marketTradingProducts.tradingSessionReferences.length; j++) {
|
||||
let sessionReference = marketTradingProducts.tradingSessionReferences[j]
|
||||
UI.projects.superalgos.utilities.menu.menuClick(sessionReference, 'Add All Trading Mine Products', true)
|
||||
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(sessionReference.tradingMineProducts, 'Add All Data Products', true)
|
||||
sessionReference.payload.floatingObject.collapseToggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function installInChartingSpace(chartingSpace) {
|
||||
|
||||
for (let i = 0; i < dashboardsArray.length; i++) {
|
||||
/*
|
||||
If the Dashboard we need is not already there we create a new one.
|
||||
*/
|
||||
let arrayItem = dashboardsArray[i]
|
||||
let dashboard = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(chartingSpace, 'Dashboard', arrayItem.environmentNode)
|
||||
dashboard.name = arrayItem.environmentNode.type + ' ' + arrayItem.networkNode.name
|
||||
/*
|
||||
We delete all the existing Time Machines related to the market we are currently installing.
|
||||
For that, we make a new array with the existing Time Machines so that the deleting
|
||||
of each node does not affect the proccessing of the whole set.
|
||||
*/
|
||||
let timeMachines = []
|
||||
for (let i = 0; i < dashboard.timeMachines.length; i++) {
|
||||
let timeMachine = dashboard.timeMachines[i]
|
||||
timeMachines.push(timeMachine)
|
||||
}
|
||||
for (let i = 0; i < timeMachines.length; i++) {
|
||||
let timeMachine = timeMachines[i]
|
||||
let session = timeMachine.payload.referenceParent
|
||||
if (session === undefined || session.cleaned === true) {
|
||||
/*
|
||||
This is what usually happens, that the intall process make these
|
||||
time machines to lose their reference parent since the install
|
||||
process deletes them.
|
||||
*/
|
||||
UI.projects.superalgos.functionLibraries.nodeDeleter.deleteUIObject(timeMachine, rootNodes)
|
||||
continue
|
||||
}
|
||||
let marketTradingTasks = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(session, 'Market Trading Tasks', undefined, true, false, true, false)
|
||||
if (marketTradingTasks === undefined) { continue }
|
||||
if (marketTradingTasks.payload === undefined) { continue }
|
||||
if (marketTradingTasks.payload.referenceParent === undefined) { continue }
|
||||
if (marketTradingTasks.payload.referenceParent.id === market.id) {
|
||||
UI.projects.superalgos.functionLibraries.nodeDeleter.deleteUIObject(timeMachine, rootNodes)
|
||||
}
|
||||
}
|
||||
/*
|
||||
We create a time machine for each session added during the previous processing.
|
||||
*/
|
||||
for (let j = 0; j < arrayItem.sessionsArray.length; j++) {
|
||||
let session = arrayItem.sessionsArray[j]
|
||||
UI.projects.superalgos.functionLibraries.chartingSpaceFunctions.createTimeMachine(dashboard, session, node, arrayItem.networkNode, rootNodes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function uninstallMarket(node, rootNodes) {
|
||||
|
||||
node.payload.uiObject.setInfoMessage('This market is being uninstalled. Please hold on that it might take a while.')
|
||||
|
||||
setTimeout(uninstallMarketProcedure, 500)
|
||||
|
||||
function uninstallMarketProcedure() {
|
||||
let market = node
|
||||
for (let i = 0; i < rootNodes.length; i++) {
|
||||
let rootNode = rootNodes[i]
|
||||
if (rootNode.type === 'Charting Space') {
|
||||
uninstallInChartingSpace(rootNode)
|
||||
}
|
||||
}
|
||||
|
||||
node.payload.uiObject.setInfoMessage('Market uninstall is complete.')
|
||||
|
||||
function uninstallInChartingSpace(chartingSpace) {
|
||||
|
||||
/* Delete all time machines which are referencing sessions inside the market being unistalled. */
|
||||
let timeMachines = UI.projects.superalgos.utilities.branches.nodeBranchToArray(chartingSpace, 'Time Machine')
|
||||
for (let i = 0; i < timeMachines.length; i++) {
|
||||
let timeMachine = timeMachines[i]
|
||||
let session = timeMachine.payload.referenceParent
|
||||
if (session === undefined) { continue }
|
||||
let marketTradingTasks = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(session, 'Market Trading Tasks', undefined, true, false, true, false)
|
||||
if (marketTradingTasks === undefined) { continue }
|
||||
if (marketTradingTasks.payload === undefined) { continue }
|
||||
if (marketTradingTasks.payload.referenceParent === undefined) { continue }
|
||||
if (marketTradingTasks.payload.referenceParent.id === market.id) {
|
||||
UI.projects.superalgos.functionLibraries.nodeDeleter.deleteUIObject(timeMachine, rootNodes)
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete all Dashboards that does not have time machines inside. */
|
||||
let dashboardArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(chartingSpace, 'Dashboard')
|
||||
for (let i = 0; i < dashboardArray.length; i++) {
|
||||
let dashboard = dashboardArray[i]
|
||||
if (dashboard.timeMachines.length === 0) {
|
||||
UI.projects.superalgos.functionLibraries.nodeDeleter.deleteUIObject(dashboard, rootNodes)
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan Networks for the market being unistalled to delete it. */
|
||||
for (let i = 0; i < rootNodes.length; i++) {
|
||||
let rootNode = rootNodes[i]
|
||||
if (rootNode.type === 'Network') {
|
||||
uninstallInNetwork(rootNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function uninstallInNetwork(network) {
|
||||
|
||||
let marketDataTasksArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(network, 'Market Data Tasks')
|
||||
let marketTradingTasksArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(network, 'Market Trading Tasks')
|
||||
let marketLearningTasksArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(network, 'Market Learning Tasks')
|
||||
let marketDataProductsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(network, 'Market Data Products')
|
||||
let marketTradingProductsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(network, 'Market Trading Products')
|
||||
let marketLearningProductsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(network, 'Market Learning Products')
|
||||
|
||||
uninstalMarketArray(marketDataTasksArray)
|
||||
uninstalMarketArray(marketTradingTasksArray)
|
||||
uninstalMarketArray(marketLearningTasksArray)
|
||||
uninstalMarketArray(marketDataProductsArray)
|
||||
uninstalMarketArray(marketTradingProductsArray)
|
||||
uninstalMarketArray(marketLearningProductsArray)
|
||||
|
||||
function uninstalMarketArray(marketArray) {
|
||||
for (let i = 0; i < marketArray.length; i++) {
|
||||
let marketReference = marketArray[i]
|
||||
if (marketReference.payload === undefined) { continue }
|
||||
if (marketReference.payload.referenceParent === undefined) { continue }
|
||||
if (marketReference.payload.referenceParent.id === market.id) {
|
||||
UI.projects.superalgos.functionLibraries.nodeDeleter.deleteUIObject(marketReference, rootNodes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
function newSuperalgosFunctionLibraryWorkspaceFunctions() {
|
||||
thisObject = {
|
||||
addMissingWorkspaceProjects: addMissingWorkspaceProjects
|
||||
}
|
||||
|
||||
return thisObject
|
||||
|
||||
function addMissingWorkspaceProjects(node, rootNodes) {
|
||||
let url = 'ProjectNames'
|
||||
httpRequest(undefined, url, onResponse)
|
||||
|
||||
function onResponse(err, pProjects) {
|
||||
let projects = JSON.parse(pProjects)
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
let project = projects[i]
|
||||
let alreadyExist = false
|
||||
|
||||
for (let j = 0; j < rootNodes.length; j++) {
|
||||
let rootNode = rootNodes[j]
|
||||
if (rootNode.type === project + ' Project') {
|
||||
alreadyExist = true
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyExist === false) {
|
||||
let child = UI.projects.superalgos.functionLibraries.uiObjectsFromNodes.addUIObject(node, project + ' Project', rootNodes, project)
|
||||
child.project = project
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 285 KiB |
|
After Width: | Height: | Size: 8.9 MiB |
|
After Width: | Height: | Size: 11 MiB |
|
After Width: | Height: | Size: 7.9 MiB |
|
After Width: | Height: | Size: 9.5 MiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.5 KiB |
@@ -1 +1 @@
|
||||
{"type":"Data Mine","name":"Alpha","config":"{ \n\"codeName\": \"Alpha\"\n}","project":"Superalgos","sensorBots":[],"indicatorBots":[{"type":"Indicator Bot","name":"Average True Range (ATR)","config":"{\n\"codeName\": \"ATR\",\n\"repo\": \"ATR-Indicator-Bot\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Multi-Period-Market","config":"{\n \"codeName\": \"Multi-Period-Market\",\n \"description\": \"Calculates RSI.\",\n \"startMode\": {\n \"allMonths\": {\n \"run\": \"false\",\n \"minYear\": \"\",\n \"maxYear\": \"\"\n },\n \"oneMonth\": {\n \"run\": \"false\",\n \"year\": \"\",\n \"month\": \"\"\n },\n \"noTime\": {\n \"run\": \"true\"\n },\n \"fixedInterval\": {\n \"run\": \"false\",\n \"interval\": 0\n }\n },\n \"deadWaitTime\": 0,\n \"normalWaitTime\": 0,\n \"retryWaitTime\": 10000,\n \"sleepWaitTime\": 3600000,\n \"comaWaitTime\": 86400000,\n \"framework\": {\n \"name\": \"Multi-Period-Market\",\n \"startDate\": {\n },\n \"endDate\": {\n }\n }\n}","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market ATR - SMA","project":"Superalgos","id":"5cdfa018-5ade-469b-90bf-cc523ef0a46e","savedPayload":{"position":{"x":14824.467185363952,"y":17153.56240800229},"targetPosition":{"x":15051.32778510527,"y":17433.553422503435},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"2570d2c7-72e3-4131-97dc-a9f97f493e93"}}},{"type":"Output Dataset","name":"Multi-Period-Market ATR - RMA","project":"Superalgos","id":"e7e58e02-fef8-4400-9928-f29805a96f98","savedPayload":{"position":{"x":14995.21249473741,"y":17077.69824065427},"targetPosition":{"x":15051.32778510527,"y":17433.553422503435},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"67695466-be2d-43b4-9824-83baa7a08412"}}}],"outputDatasetFolders":[],"id":"b345304f-fbb3-4889-934a-8f9b4941ed29","savedPayload":{"position":{"x":15027.5645769923,"y":17379.910551027475},"targetPosition":{"x":15182.942695423619,"y":17728.650277388508},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Candles Volumes Multi-Period-Market","config":"{\"mainUtility\": \"Market Ending Point\"}","project":"Superalgos","id":"eb499527-0f18-45f9-99ab-a7bc7fabb3aa","savedPayload":{"position":{"x":15005.836154077664,"y":17146.468954298347},"targetPosition":{"x":15216.865516382564,"y":17407.20361136918},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"a0a61ba9-91cb-4ec7-92fe-134ff079de2d"}}},{"type":"Status Dependency","name":"Average True Range (ATR) Multi-Period-Market","config":"{\"mainUtility\": \"Self Reference\"}","project":"Superalgos","id":"025a6f70-c187-4b4d-aa62-6f4ebfc116ba","savedPayload":{"position":{"x":15251.795115631983,"y":17073.59332967888},"targetPosition":{"x":15216.865516382564,"y":17407.20361136918},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"8a6c8b1e-950d-4819-88a9-9c45272a0799"}}}],"dataDependencies":[{"type":"Data Dependency","name":"Candles Multi-Period-Market","project":"Superalgos","id":"f25ba171-3c78-4e4f-acb8-66446be1ce0a","savedPayload":{"position":{"x":15480.231901478768,"y":17193.677641293492},"targetPosition":{"x":15216.865516382564,"y":17407.20361136918},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"2b03494a-67d6-47f1-89b6-53fc4c9116a8"}}}],"dataMineDataDependencies":[],"id":"bf337039-bd28-4f50-89d1-5115e631e6cf","savedPayload":{"position":{"x":15223.760246305472,"y":17340.44129825625},"targetPosition":{"x":15182.942695423619,"y":17728.650277388508},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"statusReport":{"type":"Status Report","name":"New Status Report","project":"SLine truncated
|
||||
{"type":"Data Mine","name":"Alpha","config":"{ \n\"codeName\": \"Alpha\"\n}","project":"Superalgos","sensorBots":[],"indicatorBots":[{"type":"Indicator Bot","name":"Average True Range (ATR)","config":"{\n\"codeName\": \"ATR\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Multi-Period-Market","config":"{\n \"codeName\": \"Multi-Period-Market\",\n \"description\": \"Calculates RSI.\",\n \"deadWaitTime\": 0,\n \"normalWaitTime\": 0,\n \"retryWaitTime\": 10000,\n \"sleepWaitTime\": 3600000,\n \"comaWaitTime\": 86400000,\n \"framework\": {\n \"name\": \"Multi-Period-Market\"\n }\n }","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market ATR - SMA","project":"Superalgos","id":"5cdfa018-5ade-469b-90bf-cc523ef0a46e","savedPayload":{"position":{"x":14824.467185363952,"y":17153.56240800229},"targetPosition":{"x":15051.32778510527,"y":17433.553422503435},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"2570d2c7-72e3-4131-97dc-a9f97f493e93"}}},{"type":"Output Dataset","name":"Multi-Period-Market ATR - RMA","project":"Superalgos","id":"e7e58e02-fef8-4400-9928-f29805a96f98","savedPayload":{"position":{"x":14995.21249473741,"y":17077.69824065427},"targetPosition":{"x":15051.32778510527,"y":17433.553422503435},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"67695466-be2d-43b4-9824-83baa7a08412"}}}],"outputDatasetFolders":[],"id":"b345304f-fbb3-4889-934a-8f9b4941ed29","savedPayload":{"position":{"x":15027.5645769923,"y":17379.910551027475},"targetPosition":{"x":15182.942695423619,"y":17728.650277388508},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Candles Volumes Multi-Period-Market","config":"{\"mainUtility\": \"Market Ending Point\"}","project":"Superalgos","id":"eb499527-0f18-45f9-99ab-a7bc7fabb3aa","savedPayload":{"position":{"x":15005.836154077664,"y":17146.468954298347},"targetPosition":{"x":15216.865516382564,"y":17407.20361136918},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"a0a61ba9-91cb-4ec7-92fe-134ff079de2d"}}},{"type":"Status Dependency","name":"Average True Range (ATR) Multi-Period-Market","config":"{\"mainUtility\": \"Self Reference\"}","project":"Superalgos","id":"025a6f70-c187-4b4d-aa62-6f4ebfc116ba","savedPayload":{"position":{"x":15251.795115631983,"y":17073.59332967888},"targetPosition":{"x":15216.865516382564,"y":17407.20361136918},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"8a6c8b1e-950d-4819-88a9-9c45272a0799"}}}],"dataDependencies":[{"type":"Data Dependency","name":"Candles Multi-Period-Market","project":"Superalgos","id":"f25ba171-3c78-4e4f-acb8-66446be1ce0a","savedPayload":{"position":{"x":15480.231901478768,"y":17193.677641293492},"targetPosition":{"x":15216.865516382564,"y":17407.20361136918},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"2b03494a-67d6-47f1-89b6-53fc4c9116a8"}}}],"dataMineDataDependencies":[],"id":"bf337039-bd28-4f50-89d1-5115e631e6cf","savedPayload":{"position":{"x":15223.760246305472,"y":17340.44129825625},"targetPosition":{"x":15182.942695423619,"y":17728.650277388508},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"statusReport":{"type":"Status Report","name":"New Status Report","project":"Superalgos","id":"8a6c8b1e-950d-4819-88a9-9c45272a0799","savedPayload":{"position":{"x":15405.437118264057,"y":17422.346390022496},"targetPosition":{"x":15182.942695423619,"y":17728.650277388508},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{}}},"executionStartedEvent":{"type":"Execution Started Event","name":"Candles VolLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Data Mine","name":"Buddha","config":"{ \n\"codeName\": \"Buddha\"\n}","project":"Superalgos","sensorBots":[],"indicatorBots":[{"type":"Indicator Bot","name":"Candle Patterns","config":"{\n\"codeName\": \"Candle-Patterns\",\n\"repo\": \"Candle-Patterns-Bot\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Multi-Period-Market","config":"{\n \"codeName\": \"Multi-Period-Market\",\n \"description\": \"Calculates Candles Patterns for Time Frames of 01-hs and above.\",\n \"startMode\": {\n \"allMonths\": {\n \"run\": \"false\",\n \"minYear\": \"\",\n \"maxYear\": \"\"\n },\n \"oneMonth\": {\n \"run\": \"false\",\n \"year\": \"\",\n \"month\": \"\"\n },\n \"noTime\": {\n \"run\": \"true\"\n },\n \"fixedInterval\": {\n \"run\": \"false\",\n \"interval\": 0\n }\n },\n \"deadWaitTime\": 0,\n \"normalWaitTime\": 0,\n \"retryWaitTime\": 10000,\n \"sleepWaitTime\": 3600000,\n \"comaWaitTime\": 86400000,\n \"framework\": {\n \"name\": \"Multi-Period-Market\",\n \"startDate\": {\n },\n \"endDate\": {\n }\n }\n}","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Basic Candles","project":"Superalgos","id":"3e933426-1c7b-45e1-845f-08a7d2684620","savedPayload":{"position":{"x":13014.983786246557,"y":11582.257138896071},"targetPosition":{"x":13214.778358558542,"y":11672.136629478231},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"07be5b9b-e8fd-49fc-ab77-20f89fdea10f"}}},{"type":"Output Dataset","name":"Multi-Period-Market One-Candle Patterns","project":"Superalgos","id":"201dc796-db42-49ce-8b9c-1b26c0f3a0ce","savedPayload":{"position":{"x":13055.077268021229,"y":11513.03974999541},"targetPosition":{"x":13214.778358558542,"y":11672.136629478231},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"144d8665-1ff0-4db3-9340-a33fd7d0d098"}}},{"type":"Output Dataset","name":"Multi-Period-Market Two-Candles Patterns","project":"Superalgos","id":"c20616cc-d93f-40fc-904a-025fc2799a75","savedPayload":{"position":{"x":13115.919477111813,"y":11469.572073629888},"targetPosition":{"x":13214.778358558542,"y":11672.136629478231},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"8c35ce52-9dee-4d20-92e6-50ba7fd2882b"}}},{"type":"Output Dataset","name":"Multi-Period-Market Three-Candles Patterns","project":"Superalgos","id":"c8074ffc-f5ff-4cb5-8e83-0adcecc82a0c","savedPayload":{"position":{"x":13212.772990245361,"y":11473.777495327486},"targetPosition":{"x":13214.778358558542,"y":11672.136629478231},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"087fc67e-78f9-4204-ba5e-8b670566a716"}}}],"outputDatasetFolders":[],"id":"0dc09316-0987-4d22-b600-bd3868942026","savedPayload":{"position":{"x":13214.778358558542,"y":11672.136629478231},"targetPosition":{"x":13428.975206324332,"y":11986.086624547845},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Candle Patterns Multi-Period-Market","config":"{\"mainUtility\": \"Self Reference\"}","project":"Superalgos","id":"2d079388-93e4-4005-b392-c4a997904ccb","savedPayload":{"position":{"x":13237.534092975908,"y":11373.149986684633},"targetPosition":{"x":13395.171017360753,"y":11533.418739091607},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"401fbf30-8faa-40e9-9707-fac2d35f6195"}}},{"type":"Status Dependency","name":"Candles Volumes Multi-Period-Market","config":"{ \n\"mainUtility\": \"Market Starting Point\"\n}","project":"Superalgos","id":"418e1725-b690-4a55-b5f7-a4a92465c162","savedPayload":{"position":{"x":13379.394277197825,"y":11319.028125288029},"targetPosition":{"x":13395.171017360753,"y":11533.418739091607},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanLine truncated
|
||||
{"type":"Data Mine","name":"Buddha","config":"{ \n\"codeName\": \"Buddha\"\n}","project":"Superalgos","sensorBots":[],"indicatorBots":[{"type":"Indicator Bot","name":"Candle Patterns","config":"{\n\"codeName\": \"Candle-Patterns\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Multi-Period-Market","config":"{\n \"codeName\": \"Multi-Period-Market\",\n \"description\": \"Calculates Candles Patterns for Time Frames of 01-hs and above.\",\n \"deadWaitTime\": 0,\n \"normalWaitTime\": 0,\n \"retryWaitTime\": 10000,\n \"sleepWaitTime\": 3600000,\n \"comaWaitTime\": 86400000,\n \"framework\": {\n \"name\": \"Multi-Period-Market\"\n }\n }","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Basic Candles","project":"Superalgos","id":"3e933426-1c7b-45e1-845f-08a7d2684620","savedPayload":{"position":{"x":3129.041401383918,"y":17452.35686716615},"targetPosition":{"x":3328.835973695903,"y":17542.236357748305},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"07be5b9b-e8fd-49fc-ab77-20f89fdea10f"}}},{"type":"Output Dataset","name":"Multi-Period-Market One-Candle Patterns","project":"Superalgos","id":"201dc796-db42-49ce-8b9c-1b26c0f3a0ce","savedPayload":{"position":{"x":3169.134883158589,"y":17383.139478265486},"targetPosition":{"x":3328.835973695903,"y":17542.236357748305},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"144d8665-1ff0-4db3-9340-a33fd7d0d098"}}},{"type":"Output Dataset","name":"Multi-Period-Market Two-Candles Patterns","project":"Superalgos","id":"c20616cc-d93f-40fc-904a-025fc2799a75","savedPayload":{"position":{"x":3229.9770922491734,"y":17339.671801899964},"targetPosition":{"x":3328.835973695903,"y":17542.236357748305},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"8c35ce52-9dee-4d20-92e6-50ba7fd2882b"}}},{"type":"Output Dataset","name":"Multi-Period-Market Three-Candles Patterns","project":"Superalgos","id":"c8074ffc-f5ff-4cb5-8e83-0adcecc82a0c","savedPayload":{"position":{"x":3326.830605382722,"y":17343.877223597563},"targetPosition":{"x":3328.835973695903,"y":17542.236357748305},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"087fc67e-78f9-4204-ba5e-8b670566a716"}}}],"outputDatasetFolders":[],"id":"0dc09316-0987-4d22-b600-bd3868942026","savedPayload":{"position":{"x":3328.835973695903,"y":17542.236357748305},"targetPosition":{"x":3543.032821461693,"y":17856.18635281792},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Candle Patterns Multi-Period-Market","config":"{\"mainUtility\": \"Self Reference\"}","project":"Superalgos","id":"2d079388-93e4-4005-b392-c4a997904ccb","savedPayload":{"position":{"x":3351.5917081132684,"y":17243.24971495471},"targetPosition":{"x":3509.228632498114,"y":17403.518467361682},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"401fbf30-8faa-40e9-9707-fac2d35f6195"}}},{"type":"Status Dependency","name":"Candles Volumes Multi-Period-Market","config":"{ \n\"mainUtility\": \"Market Starting Point\"\n}","project":"Superalgos","id":"418e1725-b690-4a55-b5f7-a4a92465c162","savedPayload":{"position":{"x":3493.451892335186,"y":17189.127853558104},"targetPosition":{"x":3509.228632498114,"y":17403.518467361682},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"a0a61ba9-91cb-4ec7-92fe-134ff079de2d"}}}],"dataDependencies":[{"type":"Data Dependency","name":"Candles Multi-Period-Market","project":"Superalgos","id":"85c548fd-9ef7-4936-a86d-2a206cf90039","savedPayload":{"position":{"x":3649.480915739696,"y":17240.712195185763},"targetPosition":{"x":3509.228632498114,"y":17Line truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Data Mine","name":"Masters","config":"{\n\"codeName\": \"Masters\"\n}","project":"Superalgos","sensorBots":[{"type":"Sensor Bot","name":"Exchange Raw Data","config":"{\n\"codeName\": \"Exchange-Raw-Data\",\n\"repo\": \"Exchange-Raw-Data-Sensor-Bot\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Historic-OHLCVs","config":"{\n \"codeName\": \"Historic-OHLCVs\",\n \"description\": \"Retrieves and saves historical maket data\",\n \"startMode\": {\n \"noTime\": {\n \"run\": \"true\"\n },\n \"fixedInterval\": {\n \"run\": \"false\",\n \"interval\": 0\n }\n },\n \"deadWaitTime\": 0,\n \"normalWaitTime\": 60000,\n \"retryWaitTime\": 10000\n}","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[],"outputDatasetFolders":[],"id":"dfe2556e-a765-4e38-9d30-7f91090c0069","savedPayload":{"position":{"x":7743.093065585781,"y":17657.26070065566},"targetPosition":{"x":7723.051525995295,"y":18063.790438218573},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Exchange Raw Data Historic-OHLCVs","config":"{\n \"mainUtility\": \"Self Reference\"\n}","project":"Superalgos","id":"ea39c98b-18e2-44ce-9f7f-86a8a76a688a","savedPayload":{"position":{"x":8159.968121568774,"y":17392.017795274412},"targetPosition":{"x":7941.750591738466,"y":17727.773847360382},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":1,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"181c7c34-7243-497a-9ddb-1b0067c6d66e"}}}],"dataDependencies":[],"dataMineDataDependencies":[],"id":"5c7fae5a-6da6-4864-a167-f2f21d578c72","savedPayload":{"position":{"x":7941.750591738466,"y":17727.773847360382},"targetPosition":{"x":7723.051525995295,"y":18063.790438218573},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"statusReport":{"type":"Status Report","name":"New Status Report","project":"Superalgos","id":"181c7c34-7243-497a-9ddb-1b0067c6d66e","savedPayload":{"position":{"x":8080.14992890308,"y":17881.860565405637},"targetPosition":{"x":7723.051525995295,"y":18063.790438218573},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"executionStartedEvent":{"type":"Execution Started Event","name":"","project":"Superalgos","id":"957e7e3a-b167-40be-93b5-9ba4ceff56e5","savedPayload":{"position":{"x":8123.742665378901,"y":18084.134120101407},"targetPosition":{"x":7723.051525995295,"y":18063.790438218573},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"executionFinishedEvent":{"type":"Execution Finished Event","name":"New Execution Finished Event","project":"Superalgos","id":"fe40a546-43ee-49df-908a-7e72f598f0cd","savedPayload":{"position":{"x":8067.94916479235,"y":18272.098978495884},"targetPosition":{"x":7723.051525995295,"y":18063.790438218573},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc","savedPayload":{"position":{"x":7723.051525995295,"y":18063.790438218573},"targetPosition":{"x":7327.141714623944,"y":18266.006678666803},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}}],"products":[{"type":"Product Definition","name":"Trades","config":"{\n\"codeName\": \"Trades\"\n}","project":"Superalgos","datasets":[{"type":"Dataset Definition","name":"Trades","config":"{\n\"codeName\": \"Trades\"\n}","project":"Superalgos","id":"fbb7c17e-a909-4fa2-b3c5-eb8ca86297c4","savedPayload":{"position":{"x":7988.166640893156,"y":18161.91023332179},"targetPosition":{"x":7789.749141672932,"y":18193.51426197839},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":1,"distanceToParent":2,"arrangementStyle":0},"uiObject":{}}}],"id":"38dbb942-a15b-450b-a867-02a94030965f","savedPayload":{"position":{"x":7789.749141672932,"y":18193.51426197839},"targetPosition":{"x":7327.141714623944,"y":18266.006678666803},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Product Definition","name"Line truncated
|
||||
{"type":"Data Mine","name":"Masters","config":"{\n\"codeName\": \"Masters\"\n}","project":"Superalgos","sensorBots":[{"type":"Sensor Bot","name":"Exchange Raw Data","config":"{\n\"codeName\": \"Exchange-Raw-Data\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Historic-OHLCVs","config":"{\n \"codeName\": \"Historic-OHLCVs\",\n \"description\": \"Retrieves and saves historical maket data\",\n \"deadWaitTime\": 0,\n \"normalWaitTime\": 60000,\n \"retryWaitTime\": 10000,\n \"botModule\": \"Exchange Raw Data Historic OHLCVs\"\n}","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[],"outputDatasetFolders":[],"id":"dfe2556e-a765-4e38-9d30-7f91090c0069","savedPayload":{"position":{"x":7542.108005075513,"y":17855.768569069416},"targetPosition":{"x":7502.950147409498,"y":18153.20202748156},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Exchange Raw Data Historic-OHLCVs","config":"{\n \"mainUtility\": \"Self Reference\"\n}","project":"Superalgos","id":"ea39c98b-18e2-44ce-9f7f-86a8a76a688a","savedPayload":{"position":{"x":7868.207004814731,"y":17677.190023306815},"targetPosition":{"x":7685.578576112114,"y":17915.196025394187},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":1,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"181c7c34-7243-497a-9ddb-1b0067c6d66e"}}}],"dataDependencies":[],"dataMineDataDependencies":[],"id":"5c7fae5a-6da6-4864-a167-f2f21d578c72","savedPayload":{"position":{"x":7685.578576112114,"y":17915.196025394187},"targetPosition":{"x":7502.950147409498,"y":18153.20202748156},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"statusReport":{"type":"Status Report","name":"New Status Report","project":"Superalgos","id":"181c7c34-7243-497a-9ddb-1b0067c6d66e","savedPayload":{"position":{"x":7780.114007162883,"y":18038.396997772034},"targetPosition":{"x":7502.950147409498,"y":18153.20202748156},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"executionStartedEvent":{"type":"Execution Started Event","name":"","project":"Superalgos","id":"957e7e3a-b167-40be-93b5-9ba4ceff56e5","savedPayload":{"position":{"x":7800.383605821641,"y":18192.359885147573},"targetPosition":{"x":7502.950147409498,"y":18153.20202748156},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"executionFinishedEvent":{"type":"Execution Finished Event","name":"New Execution Finished Event","project":"Superalgos","id":"fe40a546-43ee-49df-908a-7e72f598f0cd","savedPayload":{"position":{"x":7740.956149496868,"y":18335.830456184176},"targetPosition":{"x":7502.950147409498,"y":18153.20202748156},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc","savedPayload":{"position":{"x":7502.950147409498,"y":18153.20202748156},"targetPosition":{"x":7225.786287656112,"y":18268.007057191084},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}}],"products":[{"type":"Product Definition","name":"Candles","config":"{\n\"codeName\": \"Candles\"\n}","project":"Superalgos","datasets":[{"type":"Dataset Definition","name":"One-Min","config":"{\n\"codeName\": \"One-Min\"\n}","project":"Superalgos","id":"1c3696e4-c28e-4744-9100-706d6dce0c3c","savedPayload":{"position":{"x":7675.786287656112,"y":18268.007057191084},"targetPosition":{"x":7525.786287656112,"y":18268.007057191084},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":1,"distanceToParent":2,"arrangementStyle":0},"uiObject":{}}}],"id":"2443883b-6959-42a3-ae3b-ef3102ffcdcc","savedPayload":{"position":{"x":7525.786287656112,"y":18268.007057191084},"targetPosition":{"x":7225.786287656112,"y":18268.007057191084},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Product Definition","name":"Volumes","config":"{\n\"codeName\": \"Volumes\"\n}","project":"Superalgos","datasets":[{"type":"Dataset Definition","name":"One-Min","config":"{\n\"codeName\": \"One-Min\"\n}","proLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Data Mine","name":"Samurai","config":"{\n\"codeName\": \"Samurai\"\n}","project":"Superalgos","sensorBots":[],"indicatorBots":[{"type":"Indicator Bot","name":"Candles Probabilities","config":"{\n\"codeName\": \"Candles-Probabilities\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Multi-Period-Market","config":"{\n \"codeName\": \"Multi-Period-Market\",\n \"description\": \"Calculates SMAs for Time Frames of 01-hs and above.\",\n \"startMode\": {\n \"allMonths\": {\n \"run\": \"false\",\n \"minYear\": \"\",\n \"maxYear\": \"\"\n },\n \"oneMonth\": {\n \"run\": \"false\",\n \"year\": \"\",\n \"month\": \"\"\n },\n \"noTime\": {\n \"run\": \"true\"\n },\n \"fixedInterval\": {\n \"run\": \"false\",\n \"interval\": 0\n }\n },\n \"deadWaitTime\": 0,\n \"normalWaitTime\": 0,\n \"retryWaitTime\": 10000,\n \"sleepWaitTime\": 3600000,\n \"comaWaitTime\": 86400000,\n \"framework\": {\n \"name\": \"Multi-Period-Market\",\n \"startDate\": {\n },\n \"endDate\": {\n }\n }\n}","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Candles Probabilities","project":"Superalgos","id":"ab027b2e-4e02-4c71-8da5-6b43c37de20b","savedPayload":{"position":{"x":24441.807558180073,"y":11178.172754360203},"targetPosition":{"x":24757.91289199851,"y":11360.695699284031},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"85c67513-347a-4948-9121-dee04543fcff"}}}],"outputDatasetFolders":[],"id":"1a087bb8-af2f-4384-85dd-c86d4b39aeff","savedPayload":{"position":{"x":24740.813740813894,"y":11764.307395546577},"targetPosition":{"x":25087.495634870367,"y":11964.565651629404},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Candles Volumes Multi-Period-Market","config":"{\"mainUtility\": \"Market Ending Point\"}","project":"Superalgos","id":"09588f6b-2193-4c9e-bc33-2ac075e8e4f4","savedPayload":{"position":{"x":25757.82661988232,"y":10782.55282705661},"targetPosition":{"x":25863.974750655703,"y":11140.122654848603},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"a0a61ba9-91cb-4ec7-92fe-134ff079de2d"}}},{"type":"Status Dependency","name":"Candles Probabilities Multi-Period-Market","config":"{ \n\"mainUtility\": \"Self Reference|Market Starting Point|Market Ending Point\"\n}","project":"Superalgos","id":"83721123-d178-4ab3-8d6f-da06e8416eb8","savedPayload":{"position":{"x":25902.870176218516,"y":10769.51496828574},"targetPosition":{"x":25863.974750655703,"y":11140.122654848603},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"24ca1130-0386-4088-9417-48eb5d8ac96a"}}}],"dataDependencies":[{"type":"Data Dependency","name":"Candles Multi-Period-Market","project":"Superalgos","id":"2cfeb861-3ce6-4f63-b974-acc395f744cc","savedPayload":{"position":{"x":26042.027883264192,"y":10813.091690317255},"targetPosition":{"x":25863.974750655703,"y":11140.122654848603},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"2b03494a-67d6-47f1-89b6-53fc4c9116a8"}}}],"dataMineDataDependencies":[],"id":"08845d0d-a0a1-4d26-bb44-1072dfcf0b07","savedPayload":{"position":{"x":24887.60865246401,"y":11617.60490303291},"targetPosition":{"x":25087.495634870367,"y":11964.565651629404},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"statusReport":{"type":"Status Report","name":"New Status Report","project":"Superalgos","id":"24ca1130-0386-4088-9417-48eb5d8ac96a","savedPayload":{"position":{"x":25087.495721365332,"y":11563.948027561915},"targetPosition":{"x":25087.495634870367,"y":11964.565651629404},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"executionStartedEvent":{"type":"Execution Started Event","name":"Candles Volumes Multi-Period-Market","project":"SLine truncated
|
||||
{"type":"Data Mine","name":"Samurai","config":"{\n\"codeName\": \"Samurai\"\n}","project":"Superalgos","sensorBots":[],"indicatorBots":[{"type":"Indicator Bot","name":"Candles Probabilities","config":"{\n\"codeName\": \"Candles-Probabilities\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Multi-Period-Market","config":"{\n \"codeName\": \"Multi-Period-Market\",\n \"description\": \"Calculates SMAs for Time Frames of 01-hs and above.\",\n \"deadWaitTime\": 0,\n \"normalWaitTime\": 0,\n \"retryWaitTime\": 10000,\n \"sleepWaitTime\": 3600000,\n \"comaWaitTime\": 86400000,\n \"framework\": {\n \"name\": \"Multi-Period-Market\"\n }\n }","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Candles Probabilities","project":"Superalgos","id":"ab027b2e-4e02-4c71-8da5-6b43c37de20b","savedPayload":{"position":{"x":17017.002939912152,"y":17072.851514913826},"targetPosition":{"x":17333.108273730588,"y":17255.374459837658},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"85c67513-347a-4948-9121-dee04543fcff"}}}],"outputDatasetFolders":[],"id":"1a087bb8-af2f-4384-85dd-c86d4b39aeff","savedPayload":{"position":{"x":17561.343925622532,"y":17819.598525719965},"targetPosition":{"x":17821.151546757865,"y":17969.598525719965},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Candles Volumes Multi-Period-Market","config":"{\"mainUtility\": \"Market Ending Point\"}","project":"Superalgos","id":"09588f6b-2193-4c9e-bc33-2ac075e8e4f4","savedPayload":{"position":{"x":18333.022001614398,"y":16677.231587610237},"targetPosition":{"x":18439.170132387782,"y":17034.801415402228},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"a0a61ba9-91cb-4ec7-92fe-134ff079de2d"}}},{"type":"Status Dependency","name":"Candles Probabilities Multi-Period-Market","config":"{ \n\"mainUtility\": \"Self Reference|Market Starting Point|Market Ending Point\"\n}","project":"Superalgos","id":"83721123-d178-4ab3-8d6f-da06e8416eb8","savedPayload":{"position":{"x":18478.065557950595,"y":16664.193728839367},"targetPosition":{"x":18439.170132387782,"y":17034.801415402228},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"24ca1130-0386-4088-9417-48eb5d8ac96a"}}}],"dataDependencies":[{"type":"Data Dependency","name":"Candles Multi-Period-Market","project":"Superalgos","id":"2cfeb861-3ce6-4f63-b974-acc395f744cc","savedPayload":{"position":{"x":18617.22326499627,"y":16707.770450870878},"targetPosition":{"x":18439.170132387782,"y":17034.801415402228},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"2b03494a-67d6-47f1-89b6-53fc4c9116a8"}}}],"dataMineDataDependencies":[],"id":"08845d0d-a0a1-4d26-bb44-1072dfcf0b07","savedPayload":{"position":{"x":17671.151546757865,"y":17709.79090458463},"targetPosition":{"x":17821.151546757865,"y":17969.598525719965},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"statusReport":{"type":"Status Report","name":"New Status Report","project":"Superalgos","id":"24ca1130-0386-4088-9417-48eb5d8ac96a","savedPayload":{"position":{"x":17821.151546757865,"y":17669.598525719965},"targetPosition":{"x":17821.151546757865,"y":17969.598525719965},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"executionStartedEvent":{"type":"Execution Started Event","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"82529746-2044-48f0-b1f6-d1454ba5682d","savedPayload":{"position":{"x":17971.151546757865,"y":17709.79090458463},"targetPosition":{"x":17821.151546757865,"y":17969.598525719965},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Execution FinisLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Data Mine","name":"Sparta","config":"{\n\"codeName\": \"Sparta\"\n}","project":"Superalgos","sensorBots":[],"indicatorBots":[{"type":"Indicator Bot","name":"Simple Moving Average (SMA)","config":"{\n\"codeName\": \"SMA\",\n\"repo\": \"SMA-Indicator-Bot\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Multi-Period-Market","config":"{\n \"codeName\": \"Multi-Period-Market\",\n \"description\": \"Calculates SMAs for Time Frames of 01-hs and above.\",\n \"startMode\": {\n \"allMonths\": {\n \"run\": \"false\",\n \"minYear\": \"\",\n \"maxYear\": \"\"\n },\n \"oneMonth\": {\n \"run\": \"false\",\n \"year\": \"\",\n \"month\": \"\"\n },\n \"noTime\": {\n \"run\": \"true\"\n },\n \"fixedInterval\": {\n \"run\": \"false\",\n \"interval\": 0\n }\n },\n \"deadWaitTime\": 0,\n \"normalWaitTime\": 0,\n \"retryWaitTime\": 10000,\n \"sleepWaitTime\": 3600000,\n \"comaWaitTime\": 86400000,\n \"framework\": {\n \"name\": \"Multi-Period-Market\",\n \"startDate\": {\n },\n \"endDate\": {\n }\n }\n}","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Popular SMAs","project":"Superalgos","id":"5302effb-1f09-4a30-9f71-6956b8b9ca88","savedPayload":{"position":{"x":10609.044651705652,"y":17428.90566641547},"targetPosition":{"x":10995.890269605332,"y":17540.32974347027},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"3b21f9d7-2cbc-4c23-80c8-cc5e5b06a22c"}}},{"type":"Output Dataset","name":"Multi-Period-Market Base11 SMAs","project":"Superalgos","id":"8221593c-6298-4b4c-bfc2-cffbc9e5cd0f","savedPayload":{"position":{"x":10652.515125452519,"y":17324.96443352291},"targetPosition":{"x":10995.890269605332,"y":17540.32974347027},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"af9b9cef-2a74-486f-b79e-047d68669a1f"}}},{"type":"Output Dataset","name":"Multi-Period-Market Base7 SMAs","project":"Superalgos","id":"aabd0857-b4fc-404a-8967-967475ed3993","savedPayload":{"position":{"x":10721.675023375876,"y":17240.07387795538},"targetPosition":{"x":10995.890269605332,"y":17540.32974347027},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"78a6ef37-4df8-4ac8-83a0-c9a732467c59"}}},{"type":"Output Dataset","name":"Multi-Period-Market Base6 SMAs","project":"Superalgos","id":"dd00a77a-761e-404b-9e44-627335668112","savedPayload":{"position":{"x":10809.956405495142,"y":17178.031642194932},"targetPosition":{"x":10995.890269605332,"y":17540.32974347027},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"c0862b3d-d35a-4d3e-8d80-258b8a01c37c"}}},{"type":"Output Dataset","name":"Muti-Period-Market Base5 SMAs","project":"Superalgos","id":"b6426833-d2c7-4300-b610-801e12a7edfd","savedPayload":{"position":{"x":10936.584878620257,"y":17141.406608785455},"targetPosition":{"x":10995.890269605332,"y":17540.32974347027},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Muti-Period-Market","id":"a5d28568-fb58-469a-9820-b9f0e8eab705"}}}],"outputDatasetFolders":[],"id":"85a56739-9351-444b-95e9-a57470dca38a","savedPayload":{"position":{"x":10995.890269605332,"y":17540.32974347027},"targetPosition":{"x":11302.555356491408,"y":17880.959414907546},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Simple Moving Average (SMA) Multi-Period-Market","config":"{\"mainUtility\": \"Self Reference\"}","project":"Superalgos","id":"d49d1e94-1960-4121-8e40-be8af52947ee","savedPayload":{"position":{"x":11067.618896327327,"y":17267.479023725446},"targetPosition":{"x":11205.707967556615,"y":17422.24521572421},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New StaLine truncated
|
||||
{"type":"Data Mine","name":"Sparta","config":"{\n\"codeName\": \"Sparta\"\n}","project":"Superalgos","sensorBots":[],"indicatorBots":[{"type":"Indicator Bot","name":"Simple Moving Average (SMA)","config":"{\n\"codeName\": \"SMA\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Multi-Period-Market","config":"{\n \"codeName\": \"Multi-Period-Market\",\n \"description\": \"Calculates SMAs for Time Frames of 01-hs and above.\",\n \"deadWaitTime\": 0,\n \"normalWaitTime\": 0,\n \"retryWaitTime\": 10000,\n \"sleepWaitTime\": 3600000,\n \"comaWaitTime\": 86400000,\n \"framework\": {\n \"name\": \"Multi-Period-Market\"\n }\n }","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Popular SMAs","project":"Superalgos","id":"5302effb-1f09-4a30-9f71-6956b8b9ca88","savedPayload":{"position":{"x":10609.044651705652,"y":17428.90566641547},"targetPosition":{"x":10995.890269605332,"y":17540.32974347027},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"3b21f9d7-2cbc-4c23-80c8-cc5e5b06a22c"}}},{"type":"Output Dataset","name":"Multi-Period-Market Base11 SMAs","project":"Superalgos","id":"8221593c-6298-4b4c-bfc2-cffbc9e5cd0f","savedPayload":{"position":{"x":10652.515125452519,"y":17324.96443352291},"targetPosition":{"x":10995.890269605332,"y":17540.32974347027},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"af9b9cef-2a74-486f-b79e-047d68669a1f"}}},{"type":"Output Dataset","name":"Multi-Period-Market Base7 SMAs","project":"Superalgos","id":"aabd0857-b4fc-404a-8967-967475ed3993","savedPayload":{"position":{"x":10721.675023375876,"y":17240.07387795538},"targetPosition":{"x":10995.890269605332,"y":17540.32974347027},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"78a6ef37-4df8-4ac8-83a0-c9a732467c59"}}},{"type":"Output Dataset","name":"Multi-Period-Market Base6 SMAs","project":"Superalgos","id":"dd00a77a-761e-404b-9e44-627335668112","savedPayload":{"position":{"x":10809.956405495142,"y":17178.031642194932},"targetPosition":{"x":10995.890269605332,"y":17540.32974347027},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"c0862b3d-d35a-4d3e-8d80-258b8a01c37c"}}},{"type":"Output Dataset","name":"Muti-Period-Market Base5 SMAs","project":"Superalgos","id":"b6426833-d2c7-4300-b610-801e12a7edfd","savedPayload":{"position":{"x":10936.584878620257,"y":17141.406608785455},"targetPosition":{"x":10995.890269605332,"y":17540.32974347027},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Muti-Period-Market","id":"a5d28568-fb58-469a-9820-b9f0e8eab705"}}}],"outputDatasetFolders":[],"id":"85a56739-9351-444b-95e9-a57470dca38a","savedPayload":{"position":{"x":10995.890269605332,"y":17540.32974347027},"targetPosition":{"x":11302.555356491408,"y":17880.959414907546},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Simple Moving Average (SMA) Multi-Period-Market","config":"{\"mainUtility\": \"Self Reference\"}","project":"Superalgos","id":"d49d1e94-1960-4121-8e40-be8af52947ee","savedPayload":{"position":{"x":11067.618896327327,"y":17267.479023725446},"targetPosition":{"x":11205.707967556615,"y":17422.24521572421},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":2,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"81346f2f-13f2-46f4-85f5-a04b4d80f455"}}},{"type":"Status Dependency","name":"Candles Volumes Multi-Period-Market","config":"{\"mainUtility\": \"Market Ending Point\"}","project":"Superalgos","id":"f7cf0949-06fc-4c98-a399-61fac1671c6e","savedPayload":{"position":{"x":11151.101786685287,"y":17208.702149919078},"targetPosition":{"x":11205.707967556615,"y":17422.24521572421},"floatingObject":{"isPinned":Line truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Data Mine","name":"Zeus","config":"{ \n\"codeName\": \"Zeus\"\n}","project":"Superalgos","sensorBots":[],"indicatorBots":[{"type":"Indicator Bot","name":"Super Trend","config":"{ \n\"codeName\": \"Super-Trend\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Multi-Period-Market","config":" {\n \"codeName\": \"Multi-Period-Market\",\n \"normalWaitTime\": 0,\n \"retryWaitTime\": 10000,\n \"framework\": {\n \"name\": \"Multi-Period-Market\"\n }\n }","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Super Trend","project":"Superalgos","id":"2412939e-1585-47f9-8d09-7ea8dd7c8bf0","savedPayload":{"position":{"x":22032.236320825206,"y":18198.423702743665},"targetPosition":{"x":22071.059177590585,"y":18343.312576687025},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":1,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"7c8e7a6f-99c8-4d90-9f44-e3e9e909eb88"}}}],"outputDatasetFolders":[],"id":"74212c63-4a69-407d-80ec-d39ee2d8df74","savedPayload":{"position":{"x":22071.059177590585,"y":18343.312576687025},"targetPosition":{"x":22109.882034355964,"y":18488.201450630386},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Super Trend Multi-Period-Market","config":"{ \n\"mainUtility\": \"Self Reference\"\n}","project":"Superalgos","id":"5a35d0d1-cfed-4893-84ab-344a77c7d252","savedPayload":{"position":{"x":22037.52774788672,"y":17938.616081608332},"targetPosition":{"x":22187.52774788672,"y":18198.423702743665},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"25f05344-3e7f-4d5f-ab1c-d72689a85764"}}},{"type":"Status Dependency","name":"Candles Volumes Multi-Period-Market","config":"{ \n\"mainUtility\": \"Market Ending Point\"\n}","project":"Superalgos","id":"2a42dd15-1e04-4826-bd5f-85d95fbae135","savedPayload":{"position":{"x":22265.17346141748,"y":17908.645954856944},"targetPosition":{"x":22187.52774788672,"y":18198.423702743665},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"a0a61ba9-91cb-4ec7-92fe-134ff079de2d"}}}],"dataDependencies":[{"type":"Data Dependency","name":"Candles Multi-Period-Market","project":"Superalgos","id":"88a45f27-a0b8-4234-b7aa-f139400305db","savedPayload":{"position":{"x":22447.335369022054,"y":18048.423702743665},"targetPosition":{"x":22187.52774788672,"y":18198.423702743665},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"2b03494a-67d6-47f1-89b6-53fc4c9116a8"}}}],"dataMineDataDependencies":[],"id":"eef38121-80a2-4471-b909-24acdc4d213a","savedPayload":{"position":{"x":22187.52774788672,"y":18198.423702743665},"targetPosition":{"x":22109.882034355964,"y":18488.201450630386},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"statusReport":{"type":"Status Report","name":"New Status Report","project":"Superalgos","id":"25f05344-3e7f-4d5f-ab1c-d72689a85764","savedPayload":{"position":{"x":22322.014068711927,"y":18276.069416274422},"targetPosition":{"x":22109.882034355964,"y":18488.201450630386},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"executionStartedEvent":{"type":"Execution Started Event","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"d9b0ffbd-c1bd-4e43-a00d-04a6b6fb470b","savedPayload":{"position":{"x":22399.659782242685,"y":18410.55573709963},"targetPosition":{"x":22109.882034355964,"y":18488.201450630386},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Execution Finished Event","name":"New Execution Finished Event","id":"1824fa00-dd30-4cdc-acc0-01c2f29056c5"}}},"executionFinishedEvent":{"type":"Execution Finished Event","name":"New Execution Finished Event","project":"Superalgos","id":"d405bfe9-74f9-4419-8288-94229cLine truncated
|
||||
{"type":"Data Mine","name":"Zeus","config":"{ \n\"codeName\": \"Zeus\"\n}","project":"Superalgos","sensorBots":[],"indicatorBots":[{"type":"Indicator Bot","name":"Super Trend","config":"{ \n\"codeName\": \"Super-Trend\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Multi-Period-Market","config":" {\n \"codeName\": \"Multi-Period-Market\",\n \"normalWaitTime\": 0,\n \"retryWaitTime\": 10000,\n \"framework\": {\n \"name\": \"Multi-Period-Market\"\n }\n }","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Super Trend","project":"Superalgos","id":"2412939e-1585-47f9-8d09-7ea8dd7c8bf0","savedPayload":{"position":{"x":21786.83642206419,"y":17775.938049371594},"targetPosition":{"x":21825.659278829567,"y":17920.826923314955},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":1,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"7c8e7a6f-99c8-4d90-9f44-e3e9e909eb88"}}}],"outputDatasetFolders":[],"id":"74212c63-4a69-407d-80ec-d39ee2d8df74","savedPayload":{"position":{"x":21825.659278829567,"y":17920.826923314955},"targetPosition":{"x":21864.482135594946,"y":18065.715797258315},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":2,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"processDependencies":{"type":"Process Dependencies","name":"New Process Dependencies","project":"Superalgos","statusDependencies":[{"type":"Status Dependency","name":"Super Trend Multi-Period-Market","config":"{ \n\"mainUtility\": \"Self Reference\"\n}","project":"Superalgos","id":"5a35d0d1-cfed-4893-84ab-344a77c7d252","savedPayload":{"position":{"x":21792.127849125704,"y":17516.13042823626},"targetPosition":{"x":21942.127849125704,"y":17775.938049371594},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"25f05344-3e7f-4d5f-ab1c-d72689a85764"}}},{"type":"Status Dependency","name":"Candles Volumes Multi-Period-Market","config":"{ \n\"mainUtility\": \"Market Ending Point\"\n}","project":"Superalgos","id":"2a42dd15-1e04-4826-bd5f-85d95fbae135","savedPayload":{"position":{"x":22019.77356265646,"y":17486.160301484873},"targetPosition":{"x":21942.127849125704,"y":17775.938049371594},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Status Report","name":"New Status Report","id":"a0a61ba9-91cb-4ec7-92fe-134ff079de2d"}}}],"dataDependencies":[{"type":"Data Dependency","name":"Candles Multi-Period-Market","project":"Superalgos","id":"88a45f27-a0b8-4234-b7aa-f139400305db","savedPayload":{"position":{"x":22201.935470261036,"y":17625.938049371594},"targetPosition":{"x":21942.127849125704,"y":17775.938049371594},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"2b03494a-67d6-47f1-89b6-53fc4c9116a8"}}}],"dataMineDataDependencies":[],"id":"eef38121-80a2-4471-b909-24acdc4d213a","savedPayload":{"position":{"x":21942.127849125704,"y":17775.938049371594},"targetPosition":{"x":21864.482135594946,"y":18065.715797258315},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"statusReport":{"type":"Status Report","name":"New Status Report","project":"Superalgos","id":"25f05344-3e7f-4d5f-ab1c-d72689a85764","savedPayload":{"position":{"x":22076.61416995091,"y":17853.58376290235},"targetPosition":{"x":21864.482135594946,"y":18065.715797258315},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"executionStartedEvent":{"type":"Execution Started Event","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"d9b0ffbd-c1bd-4e43-a00d-04a6b6fb470b","savedPayload":{"position":{"x":22154.259883481667,"y":17988.070083727558},"targetPosition":{"x":21864.482135594946,"y":18065.715797258315},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Execution Finished Event","name":"New Execution Finished Event","id":"1824fa00-dd30-4cdc-acc0-01c2f29056c5"}}},"executionFinishedEvent":{"type":"Execution Finished Event","name":"New Execution Finished Event","project":"Superalgos","id":"d405bfe9-74f9-4419-8288-9422Line truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Trading Mine","name":"Masters","config":"{ \n\"codeName\": \"Masters\"\n}","project":"Superalgos","tradingBots":[{"type":"Trading Bot","name":"Low Frequency","config":"{\n\"codeName\": \"Low-Frequency\",\n\"repo\": \"Exchange-Raw-Data-Sensor-Bot\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Trading","config":"{\n \"codeName\": \"Trading\",\n \"sessionRunWaitTime\": 5000,\n \"retryWaitTime\": 10000,\n \"framework\": {\n \"name\": \"Low-Frequency-Trading-Process\"\n }\n }","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[],"outputDatasetFolders":[{"type":"Output Dataset Folder","name":"Trading Engine","project":"Superalgos","outputDatasets":[],"outputDatasetFolders":[{"type":"Output Dataset Folder","name":"Episode","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Episode Counters","project":"Superalgos","id":"ec8d74ba-a4ad-417a-b479-6bae95b8a1fe","savedPayload":{"position":{"x":24910.97457254189,"y":18457.46644293786},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"3ed03a02-381d-43fe-9faa-761728c53bd8"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Counters","project":"Superalgos","id":"22b0af33-8c2f-4194-839b-affd18f298d5","savedPayload":{"position":{"x":24834.601232363748,"y":18490.07023931273},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"15f5b150-f1cf-403c-8cb9-2c7c4e1db8e8"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Statistics","project":"Superalgos","id":"23ab91ae-2e78-4993-bb69-855f69cef1ce","savedPayload":{"position":{"x":24753.53736157276,"y":18508.085329665024},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"fc9dc0f7-35e0-4548-bb91-f920825d694f"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Statistics","project":"Superalgos","id":"d0a4515a-279d-4c27-8de2-168108861242","savedPayload":{"position":{"x":24670.543493063306,"y":18510.89823169951},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"91953362-8751-4440-a898-21245cd47c15"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Candle","project":"Superalgos","id":"7fc80977-5b37-413e-8107-0a89a16e08b0","savedPayload":{"position":{"x":24588.445883487308,"y":18498.413155411115},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"17fb41f5-61b5-4433-9a10-950ff8216a7e"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Candle","project":"Superalgos","id":"a6888750-1043-420c-9253-633e1399c5e4","savedPayload":{"position":{"x":24510.040268473647,"y":18471.05526509864},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"bbc9467d-28bf-432b-9e49-582d1bcabfb9"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Balances","project":"Superalgos","id":"0ad114df-f076-4a86-8c62-4c4a146da73c","savedPayload":{"position":{"x":24437.996657204443,"y":18429.756200904503},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"acddff59-b51b-4b45-b58f-71d4077755ee"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Balances","project":"Superalgos","id":"04b51302-957d-4365-ad55-9f89d60e261c","savedPayload":{"position":{"x":24374.76840845468,"y":18375.922352927064},"targetPosition":{"x":24696.86240363471,"y":18061.6685410663Line truncated
|
||||
{"type":"Trading Mine","name":"Masters","config":"{ \n\"codeName\": \"Masters\"\n}","project":"Superalgos","tradingBots":[{"type":"Trading Bot","name":"Low Frequency","config":"{\n\"codeName\": \"Low-Frequency\"\n}","project":"Superalgos","processes":[{"type":"Process Definition","name":"Trading","config":"{\n \"codeName\": \"Trading\",\n \"sessionRunWaitTime\": 5000,\n \"retryWaitTime\": 10000,\n \"framework\": {\n \"name\": \"Low-Frequency-Trading-Process\"\n }\n }","project":"Superalgos","processOutput":{"type":"Process Output","name":"New Process Output","project":"Superalgos","outputDatasets":[],"outputDatasetFolders":[{"type":"Output Dataset Folder","name":"Trading Engine","project":"Superalgos","outputDatasets":[],"outputDatasetFolders":[{"type":"Output Dataset Folder","name":"Episode","project":"Superalgos","outputDatasets":[{"type":"Output Dataset","name":"Multi-Period-Market Episode Counters","project":"Superalgos","id":"ec8d74ba-a4ad-417a-b479-6bae95b8a1fe","savedPayload":{"position":{"x":24910.97457254189,"y":18457.46644293786},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"3ed03a02-381d-43fe-9faa-761728c53bd8"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Counters","project":"Superalgos","id":"22b0af33-8c2f-4194-839b-affd18f298d5","savedPayload":{"position":{"x":24834.601232363748,"y":18490.07023931273},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"15f5b150-f1cf-403c-8cb9-2c7c4e1db8e8"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Statistics","project":"Superalgos","id":"23ab91ae-2e78-4993-bb69-855f69cef1ce","savedPayload":{"position":{"x":24753.53736157276,"y":18508.085329665024},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"fc9dc0f7-35e0-4548-bb91-f920825d694f"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Statistics","project":"Superalgos","id":"d0a4515a-279d-4c27-8de2-168108861242","savedPayload":{"position":{"x":24670.543493063306,"y":18510.89823169951},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"91953362-8751-4440-a898-21245cd47c15"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Candle","project":"Superalgos","id":"7fc80977-5b37-413e-8107-0a89a16e08b0","savedPayload":{"position":{"x":24588.445883487308,"y":18498.413155411115},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"17fb41f5-61b5-4433-9a10-950ff8216a7e"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Candle","project":"Superalgos","id":"a6888750-1043-420c-9253-633e1399c5e4","savedPayload":{"position":{"x":24510.040268473647,"y":18471.05526509864},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Daily","id":"bbc9467d-28bf-432b-9e49-582d1bcabfb9"}}},{"type":"Output Dataset","name":"Multi-Period-Market Episode Balances","project":"Superalgos","id":"0ad114df-f076-4a86-8c62-4c4a146da73c","savedPayload":{"position":{"x":24437.996657204443,"y":18429.756200904503},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{},"referenceParent":{"type":"Dataset Definition","name":"Multi-Period-Market","id":"acddff59-b51b-4b45-b58f-71d4077755ee"}}},{"type":"Output Dataset","name":"Multi-Period-Daily Episode Balances","project":"Superalgos","id":"04b51302-957d-4365-ad55-9f89d60e261c","savedPayload":{"position":{"x":24374.76840845468,"y":18375.922352927064},"targetPosition":{"x":24696.86240363471,"y":18061.668541066385},"floatingObject":{"isPinned":false,"isFroLine truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"Trading System","name":"BB Top Bounce","config":"{ \n\"codeName\": \"\"\n}","project":"Superalgos","tradingStrategies":[{"type":"Trading Strategy","name":"S1 - 3H Down","project":"Superalgos","triggerStage":{"type":"Trigger Stage","name":"New Trigger Stage","project":"Superalgos","triggerOn":{"type":"Trigger On Event","name":"New Trigger On Event","project":"Superalgos","situations":[{"type":"Situation","name":"New Situation","project":"Superalgos","conditions":[{"type":"Condition","name":"Previous Breakup","project":"Superalgos","javascriptCode":{"type":"Javascript Code","name":"New Javascript Code","code":"chart.at01hs.candle.previous.close > chart.at01hs.bollingerBand.previous.movingAverage + chart.at01hs.bollingerBand.previous.deviation","project":"Superalgos","id":"99948a6e-e866-4339-86ba-eac367226312","savedPayload":{"position":{"x":30780.386277758334,"y":30051.498744389715},"targetPosition":{"x":31072.097253877637,"y":30121.53235354649},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":1,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"id":"f0534c68-ab47-4370-b1fd-b3be4c1c262f","savedPayload":{"position":{"x":31072.097253877637,"y":30121.53235354649},"targetPosition":{"x":31363.80822999694,"y":30191.565962703262},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Condition","name":"Current Close In","project":"Superalgos","javascriptCode":{"type":"Javascript Code","name":"New Javascript Code","code":"chart.at01hs.candle.close < chart.at01hs.bollingerBand.movingAverage + chart.at01hs.bollingerBand.deviation","project":"Superalgos","id":"d3bd1690-1f94-484b-ac3c-7be2c7be85ed","savedPayload":{"position":{"x":30878.398033371974,"y":29838.894811327777},"targetPosition":{"x":31121.103131684456,"y":30015.23038701552},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":1,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"id":"e2d7334d-cf52-44d9-a20e-5be201ca6799","savedPayload":{"position":{"x":31121.103131684456,"y":30015.23038701552},"targetPosition":{"x":31363.80822999694,"y":30191.565962703262},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Condition","name":"Current Red Candle","project":"Superalgos","javascriptCode":{"type":"Javascript Code","name":"New Javascript Code","code":"chart.at01hs.candle.close < chart.at01hs.candle.open","project":"Superalgos","id":"d1fa707f-eb75-4b1c-8117-688b9b94e539","savedPayload":{"position":{"x":31050.30909116737,"y":29679.98186409081},"targetPosition":{"x":31207.058660582155,"y":29935.773913397035},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"id":"fb71bcfb-2a40-4e8a-b8e8-b492128350a0","savedPayload":{"position":{"x":31207.058660582155,"y":29935.773913397035},"targetPosition":{"x":31363.80822999694,"y":30191.565962703262},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Condition","name":"3H Down","code":"chart.at03hs.bollingerChannel.direction * chart.atAnyTimeFrame.externalSignal.timestamp > chart.atAnyTimeFrame.externalSignal.timestamp","project":"Superalgos","javascriptCode":{"type":"Javascript Code","name":"New Javascript Code","code":"chart.at03hs.bollingerChannel.direction === \"Down\"","project":"Superalgos","id":"8c8c5128-b88b-44a5-8e36-d5c61127404f","savedPayload":{"position":{"x":31269.9475509728,"y":29598.95295834618},"targetPosition":{"x":31316.87789048487,"y":29895.25946052472},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{}}},"id":"22246178-a8f9-4ec8-b55b-36cf7a24fbff","savedPayload":{"position":{"x":31316.87789048487,"y":29895.25946052472},"targetPosition":{"x":31363.80822999694,"y":30191.565962703262},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Condition","name":"3H Medium, Steep or Extreme","project":"Superalgos","javascriptCode":{"type":"Javascript Code","name":"New Javascript Code","code":"chart.at03hs.bollingerSubChannel.slope === \"Medium\" || chart.at03hs.bollingerSubChannel.slope === \"Steep\" || chart.at03hs.bollingerSubChannel.slope === \"Extreme\" ","project":"Superalgos","id":"bf8df41c-c62f-4cd6-840e-1dd538359c3b","savedPayload":{"position":{"x":31503.875448310486,"y":29608.144010464657},"targetPosition":{"x":31433.841839153712,"y":29899.85498658396},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"diLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Workspace","name":"BB Top Bounce","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataMining":{"type":"Data Mining","name":"New Data Mining","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Masters","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Masters","project":"Superalgos","tasks":[{"type":"Task","name":"Exchange Raw Data","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Exchange Raw Data","config":"{ \n\"startDate\": \"2020-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Exchange Raw Data Historic-OHLCVs","project":"Superalgos","id":"3d9fe97d-72ad-4342-89f6-8bda778f2609","savedPayload":{"position":{"x":23467.55083912308,"y":30317.55889397751},"targetPosition":{"x":23741.61447641586,"y":30195.537901054773},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Historic-OHLCVs","id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc"}}}],"id":"b729b63c-1bd7-4fa9-9f5a-67ce189c5795","savedPayload":{"position":{"x":23741.61447641586,"y":30195.537901054773},"targetPosition":{"x":24015.67811370864,"y":30073.516908132035},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"b1fa524f-0b97-477e-bb46-8860841619bd","savedPayload":{"position":{"x":24015.67811370864,"y":30073.516908132035},"targetPosition":{"x":24289.74175100142,"y":29951.495915209296},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Candles Volumes","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Candles Volumes","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"624dfa33-e98e-4850-868d-c7efba73f277","savedPayload":{"position":{"x":23403.264330134767,"y":29842.449687591525},"targetPosition":{"x":23702.853190561138,"y":29826.74890071864},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"9f683143-a33f-42c1-9fa8-c601f01ee4e1"}}},{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Daily","project":"Superalgos","id":"63fe5d3e-42c7-4223-9f56-579e1b3c1999","savedPayload":{"position":{"x":23435.551233304628,"y":29690.551750796778},"targetPosition":{"x":23702.853190561138,"y":29826.74890071864},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"980ceb1d-7be6-454f-90d9-01ba1fd4a65d"}}}],"id":"6ccc1257-ceee-4134-a3e2-dec8224d2eff","savedPayload":{"position":{"x":23702.853190561138,"y":29826.74890071864},"targetPosition":{"x":23996.29747078128,"y":29889.12240796397},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"ff410bdc-7db8-4260-ad27-a3ec244c5bb3","savedPayload":{"position":{"x":23996.29747078128,"y":29889.12240796397},"targetPosition":{"x":24289.74175100142,"y":29951.495915209296},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Bollinger Bands","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Bollinger Bands","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Bollinger Bands Multi-Period-Market","project":"Superalgos","id":"5aaf5b42-4379-4d23-926a-f15eb36c36be","savedPayload":{"position":{"x":23636.662216802477,"y":29342.217309418353},"targetPosition":{"x":23888.263387186104,"y":29505.60901992286},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"941a0543-0cc0-4a5d-a782-728d2835c100"}}},{"type":"IndLine truncated
|
||||
{"type":"Workspace","name":"BB Top Bounce","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataTasks":{"type":"Data Tasks","name":"New Data Tasks","project":"Superalgos","projectDataTasks":[{"type":"Project Data Tasks","name":"New Project Definition","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Sparta","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Sparta","project":"Superalgos","tasks":[{"type":"Task","name":"Simple Moving Average (SMA)","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Simple Moving Average (SMA)","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Simple Moving Average (SMA) Multi-Period-Market","project":"Superalgos","id":"64a0f312-b72e-494c-8802-70ebb6238c8b","savedPayload":{"position":{"x":24860.356993272086,"y":30929.11115747996},"targetPosition":{"x":24927.356993272086,"y":31018.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"456269f6-9849-4d5f-9c8c-7cd7d1eef297"}}},{"type":"Indicator Process Instance","name":"Simple Moving Average (SMA) Multi-Period-Daily","project":"Superalgos","id":"7a44ff20-1251-4157-9741-a4c2881b179e","savedPayload":{"position":{"x":24962.356993272086,"y":31086.11115747996},"targetPosition":{"x":24927.356993272086,"y":31018.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"333ae5d7-7ec1-4f08-b206-91e3b4f2c99f"}}}],"id":"ef39e485-c27d-443b-aa74-b10b8f8d10ad","savedPayload":{"position":{"x":24927.356993272086,"y":31018.11115747996},"targetPosition":{"x":24963.356993272086,"y":31085.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"01a5f038-ab20-44fe-99b0-0d5d3c0d4bcb","savedPayload":{"position":{"x":24963.356993272086,"y":31085.11115747996},"targetPosition":{"x":24878.356993272086,"y":31053.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Exponential Moving Average (EMA)","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Exponential Moving Average (EMA)","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Exponential Moving Average (EMA) Multi-Period-Market","project":"Superalgos","id":"c95597e5-5d5c-4dd7-9510-99874a022eac","savedPayload":{"position":{"x":24816.356993272086,"y":31085.11115747996},"targetPosition":{"x":24789.356993272086,"y":31068.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"278c34a7-199d-400e-8a06-087149e3d391"}}},{"type":"Indicator Process Instance","name":"Exponential Moving Average (EMA) Multi-Period-Daily","project":"Superalgos","id":"e588dc58-d99c-4938-aaab-747d23408301","savedPayload":{"position":{"x":24833.356993272086,"y":31119.11115747996},"targetPosition":{"x":24789.356993272086,"y":31068.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"943ea24f-ee24-4eae-9b4b-e8a73122b1c2"}}}],"id":"44fefa5e-341a-43c7-8967-7545a6e229ad","savedPayload":{"position":{"x":24789.356993272086,"y":31068.11115747996},"targetPosition":{"x":24874.356993272086,"y":31135.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"1e55a456-ff9c-48bf-b9ea-01082495fcc9","savedPayload":{"position":{"x":24874.356993272086,"y":31135.11115747996},"targetPosition":{"x":24878.356993272086,"y":31053.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"Line truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Workspace","name":"Exchange Keys Tests","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataMining":{"type":"Data Mining","name":"New Data Mining","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Masters","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Masters","project":"Superalgos","tasks":[{"type":"Task","name":"Exchange Raw Data","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Exchange Raw Data","config":"{ \n\"startDate\": \"2017-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Exchange Raw Data Historic-OHLCVs","project":"Superalgos","id":"f17f9567-af83-4292-a0dc-7c1c9dbf53b8","savedPayload":{"position":{"x":23640.023749611923,"y":29498.94353234636},"targetPosition":{"x":23929.801497498644,"y":29576.589245877116},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Historic-OHLCVs","id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc"}}}],"id":"9eaa4440-c8bc-4daa-b858-efa1845087de","savedPayload":{"position":{"x":23929.801497498644,"y":29576.589245877116},"targetPosition":{"x":24219.579245385365,"y":29654.234959407873},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"97e5a05e-9463-41a4-8255-a9487df56496","savedPayload":{"position":{"x":24219.579245385365,"y":29654.234959407873},"targetPosition":{"x":24509.356993272086,"y":29731.88067293863},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Candles Volumes","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Candles Volumes","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"1ef6762d-a20c-46e0-8183-6aac6dd9073a","savedPayload":{"position":{"x":23997.224958916122,"y":29000.133396312},"targetPosition":{"x":24209.356993272086,"y":29212.265430667965},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"9f683143-a33f-42c1-9fa8-c601f01ee4e1"}}},{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Daily","project":"Superalgos","id":"7b44275e-9446-4807-b9c2-4ba1107a5295","savedPayload":{"position":{"x":24131.71127974133,"y":28922.487682781244},"targetPosition":{"x":24209.356993272086,"y":29212.265430667965},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"980ceb1d-7be6-454f-90d9-01ba1fd4a65d"}}}],"id":"78c835ef-be5b-4e74-8b0c-610afbbef304","savedPayload":{"position":{"x":24209.356993272086,"y":29212.265430667965},"targetPosition":{"x":24359.356993272086,"y":29472.073051803298},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"b4da2db7-fcae-4918-b38a-5e6966a9994b","savedPayload":{"position":{"x":24359.356993272086,"y":29472.073051803298},"targetPosition":{"x":24509.356993272086,"y":29731.88067293863},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Bollinger Bands","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Bollinger Bands","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Bollinger Bands Multi-Period-Market","project":"Superalgos","id":"22a8694f-078e-4f1f-8470-7a7b25237397","savedPayload":{"position":{"x":24664.6484203336,"y":28852.32517716519},"targetPosition":{"x":24664.6484203336,"y":29152.32517716519},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"941a0543-0cc0-4a5d-a782-728d2835c100"}}},{"tLine truncated
|
||||
{"type":"Workspace","name":"Exchange Keys Tests","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataTasks":{"type":"Data Tasks","name":"New Data Tasks","project":"Superalgos","projectDataTasks":[{"type":"Project Data Tasks","name":"Superalgos","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Masters","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Masters","project":"Superalgos","tasks":[{"type":"Task","name":"Exchange Raw Data","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Exchange Raw Data","config":"{ \n\"startDate\": \"2017-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Exchange Raw Data Historic-OHLCVs","project":"Superalgos","id":"f17f9567-af83-4292-a0dc-7c1c9dbf53b8","savedPayload":{"position":{"x":23148.696821492267,"y":29710.450985700143},"targetPosition":{"x":23448.696821492267,"y":29710.450985700143},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Historic-OHLCVs","id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc"}}}],"id":"9eaa4440-c8bc-4daa-b858-efa1845087de","savedPayload":{"position":{"x":23448.696821492267,"y":29710.450985700143},"targetPosition":{"x":23748.696821492267,"y":29710.450985700143},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"97e5a05e-9463-41a4-8255-a9487df56496","savedPayload":{"position":{"x":23748.696821492267,"y":29710.450985700143},"targetPosition":{"x":24048.696821492267,"y":29710.450985700143},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Candles Volumes","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Candles Volumes","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"1ef6762d-a20c-46e0-8183-6aac6dd9073a","savedPayload":{"position":{"x":23364.625131645007,"y":29136.186916988216},"targetPosition":{"x":23624.43275278034,"y":29286.186916988216},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"9f683143-a33f-42c1-9fa8-c601f01ee4e1"}}},{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Daily","project":"Superalgos","id":"7b44275e-9446-4807-b9c2-4ba1107a5295","savedPayload":{"position":{"x":23474.43275278034,"y":29026.379295852883},"targetPosition":{"x":23624.43275278034,"y":29286.186916988216},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"980ceb1d-7be6-454f-90d9-01ba1fd4a65d"}}}],"id":"78c835ef-be5b-4e74-8b0c-610afbbef304","savedPayload":{"position":{"x":23624.43275278034,"y":29286.186916988216},"targetPosition":{"x":23836.564787136303,"y":29498.31895134418},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"b4da2db7-fcae-4918-b38a-5e6966a9994b","savedPayload":{"position":{"x":23836.564787136303,"y":29498.31895134418},"targetPosition":{"x":24048.696821492267,"y":29710.450985700143},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Bollinger Bands","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Bollinger Bands","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Bollinger Bands Multi-Period-Market","project":"Superalgos","id":"22a8694f-078e-4f1f-8470-7a7b25237397","savedPayload":{"position":{"x":23971.05110796151,"y":28820.673237813422},"targetPosition":{"x":24048.696821492267,"y":29110.450985700143},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"ProcLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Workspace","name":"Getting Started","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataMining":{"type":"Data Mining","name":"New Data Mining","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Masters","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Masters","project":"Superalgos","tasks":[{"type":"Task","name":"Exchange Raw Data","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Exchange Raw Data","config":"{ \n\"startDate\": \"2020-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Exchange Raw Data Historic-OHLCVs","project":"Superalgos","id":"d244c564-4e86-43c7-9796-dc3b6294ec8b","savedPayload":{"position":{"x":23993.925629940142,"y":29195.742554406977},"targetPosition":{"x":24261.227587196652,"y":29331.93970432884},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Historic-OHLCVs","id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc"}}}],"id":"343313ae-5705-484d-8bf8-aed25ba61cfa","savedPayload":{"position":{"x":24261.227587196652,"y":29331.93970432884},"targetPosition":{"x":24528.529544453162,"y":29468.136854250704},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"a8f38508-1cac-4ab1-815f-d338fc813377","savedPayload":{"position":{"x":24528.529544453162,"y":29468.136854250704},"targetPosition":{"x":24795.831501709672,"y":29604.334004172568},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Candles Volumes","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Candles Volumes","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"f0ef12ed-f0fd-4b88-8e15-27cf24265a5f","savedPayload":{"position":{"x":24387.47785744149,"y":28832.96091248782},"targetPosition":{"x":24610.421305084707,"y":29033.700094395477},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"9f683143-a33f-42c1-9fa8-c601f01ee4e1"}}},{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Daily","project":"Superalgos","id":"7c8b312c-09bf-4c59-853f-1592391a9c57","savedPayload":{"position":{"x":24672.794812330034,"y":28740.255814175336},"targetPosition":{"x":24610.421305084707,"y":29033.700094395477},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"980ceb1d-7be6-454f-90d9-01ba1fd4a65d"}}}],"id":"8d58e84b-d7ef-464f-8079-0ec0887e3da3","savedPayload":{"position":{"x":24610.421305084707,"y":29033.700094395477},"targetPosition":{"x":24703.12640339719,"y":29319.017049284023},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"bf29e3bd-9386-408b-9091-042da0c53e81","savedPayload":{"position":{"x":24703.12640339719,"y":29319.017049284023},"targetPosition":{"x":24795.831501709672,"y":29604.334004172568},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Resistances and Supports","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Resistances and Supports","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Resistances and Supports Multi-Period-Market","project":"Superalgos","id":"a707814e-b81b-4102-9b5b-4e2fe969324f","savedPayload":{"position":{"x":25052.525014680516,"y":28770.141229233177},"targetPosition":{"x":25068.2258015534,"y":29069.730089659548},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"5d9b2729-43fb-4eLine truncated
|
||||
{"type":"Workspace","name":"Getting Started","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataTasks":{"type":"Data Tasks","name":"New Data Tasks","project":"Superalgos","projectDataTasks":[{"type":"Project Data Tasks","name":"Superalgos","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Masters","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Masters","project":"Superalgos","tasks":[{"type":"Task","name":"Exchange Raw Data","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Exchange Raw Data","config":"{ \n\"startDate\": \"2020-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Exchange Raw Data Historic-OHLCVs","project":"Superalgos","id":"d244c564-4e86-43c7-9796-dc3b6294ec8b","savedPayload":{"position":{"x":23490.023749611923,"y":29239.135911211026},"targetPosition":{"x":23779.801497498644,"y":29316.781624741783},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Historic-OHLCVs","id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc"}}}],"id":"343313ae-5705-484d-8bf8-aed25ba61cfa","savedPayload":{"position":{"x":23779.801497498644,"y":29316.781624741783},"targetPosition":{"x":24069.579245385365,"y":29394.42733827254},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"a8f38508-1cac-4ab1-815f-d338fc813377","savedPayload":{"position":{"x":24069.579245385365,"y":29394.42733827254},"targetPosition":{"x":24359.356993272086,"y":29472.073051803298},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Candles Volumes","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Candles Volumes","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"f0ef12ed-f0fd-4b88-8e15-27cf24265a5f","savedPayload":{"position":{"x":23799.549372136753,"y":28802.457809532632},"targetPosition":{"x":24059.356993272086,"y":28952.457809532632},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"9f683143-a33f-42c1-9fa8-c601f01ee4e1"}}},{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Daily","project":"Superalgos","id":"7c8b312c-09bf-4c59-853f-1592391a9c57","savedPayload":{"position":{"x":24059.356993272086,"y":28652.457809532632},"targetPosition":{"x":24059.356993272086,"y":28952.457809532632},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"980ceb1d-7be6-454f-90d9-01ba1fd4a65d"}}}],"id":"8d58e84b-d7ef-464f-8079-0ec0887e3da3","savedPayload":{"position":{"x":24059.356993272086,"y":28952.457809532632},"targetPosition":{"x":24209.356993272086,"y":29212.265430667965},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"bf29e3bd-9386-408b-9091-042da0c53e81","savedPayload":{"position":{"x":24209.356993272086,"y":29212.265430667965},"targetPosition":{"x":24359.356993272086,"y":29472.073051803298},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Resistances and Supports","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Resistances and Supports","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Resistances and Supports Multi-Period-Market","project":"Superalgos","id":"a707814e-b81b-4102-9b5b-4e2fe969324f","savedPayload":{"position":{"x":24437.002706802843,"y":28602.739808143135},"targetPosition":{"x":24514.6484203336,"y":28892.517556029856},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"refeLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Workspace","name":"Trading System Design Tutorials","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataMining":{"type":"Data Mining","name":"New Data Mining","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[],"id":"af949a76-a6f4-4ec6-869e-f240480eea81","savedPayload":{"position":{"x":24959.356993272086,"y":30511.30353634463},"targetPosition":{"x":25109.356993272086,"y":30771.11115747996},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Crypto Exchange","name":"Binance","id":"61ef0b8d-de6e-4e76-bdd5-996836760a4b"}}}],"id":"4df1cb4e-b9ca-4f62-bb5f-c7e262aaa22a","savedPayload":{"position":{"x":25109.356993272086,"y":30771.11115747996},"targetPosition":{"x":25259.356993272086,"y":31030.918778615294},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":1,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"learningMining":{"type":"Learning Mining","name":"New Learning Mining","project":"Superalgos","exchangeLearningTasks":[],"id":"1b19735e-0041-438f-824b-00df4f8942dd","savedPayload":{"position":{"x":25409.356993272086,"y":30771.11115747996},"targetPosition":{"x":25259.356993272086,"y":31030.918778615294},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":1,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"testingEnvironment":{"type":"Testing Environment","name":"New Testing Environment","project":"Superalgos","exchangeTradingTasks":[{"type":"Exchange Trading Tasks","name":"Binance","project":"Superalgos","marketTradingTasks":[],"id":"ba36975c-08d6-458d-b7c0-eb4684a85b5d","savedPayload":{"position":{"x":25859.356993272086,"y":31030.918778615294},"targetPosition":{"x":25559.356993272086,"y":31030.918778615294},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Crypto Exchange","name":"Binance","id":"61ef0b8d-de6e-4e76-bdd5-996836760a4b"}}}],"id":"5882d8a8-345b-4188-b1c1-797e9ff805d9","savedPayload":{"position":{"x":25559.356993272086,"y":31030.918778615294},"targetPosition":{"x":25259.356993272086,"y":31030.918778615294},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":1,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"productionEnvironment":{"type":"Production Environment","name":"New Production Environment","project":"Superalgos","exchangeTradingTasks":[{"type":"Exchange Trading Tasks","name":"Binance","project":"Superalgos","marketTradingTasks":[],"id":"d539c0ac-aaeb-4c44-9dba-ac26df819a8d","savedPayload":{"position":{"x":25559.356993272086,"y":31550.53402088596},"targetPosition":{"x":25409.356993272086,"y":31290.726399750627},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Crypto Exchange","name":"Binance","id":"61ef0b8d-de6e-4e76-bdd5-996836760a4b"}}}],"id":"65a40d20-837c-4652-8356-f8054b4e1346","savedPayload":{"position":{"x":25409.356993272086,"y":31290.726399750627},"targetPosition":{"x":25259.356993272086,"y":31030.918778615294},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":true,"angleToParent":1,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false,"shortcutKey":"u"}}},"dataStorage":{"type":"Data Storage","name":"New Data Storage","project":"Superalgos","dataMinesData":{"type":"Data Mines Data","name":"New Data Mines Data","project":"Superalgos","exchangeDataProducts":[{"type":"Exchange Data Products","name":"Binance","project":"Superalgos","marketDataProducts":[],"id":"9bc0aea4-0596-449c-91bd-4fb4cb672aa8","savedPayload":{"position":{"x":25264.6484203336,"y":31870.28189552407},"targetPosition":{"x":25187.002706802843,"y":31580.504147637348},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Crypto Exchange","name":"Binance","id":"61ef0b8d-de6e-4e76-bdd5-996836760a4b"}}}],"id":"32e7c122-fa5a-4d00-9d71-d54e890e32de","savedPayload":{"position":{"x":25187.002706802843,"y":31580.504147637348},"targetPosition":{"x":25109.356993272086,"y":31290.726399750627},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"tradingMineLine truncated
|
||||
{"type":"Workspace","name":"Trading System Design Tutorials","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataTasks":{"type":"Data Tasks","name":"New Data Tasks","project":"Superalgos","projectDataTasks":[{"type":"Project Data Tasks","name":"Superalgos","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Masters","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Masters","project":"Superalgos","tasks":[{"type":"Task","name":"Exchange Raw Data","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Exchange Raw Data","config":"{ \n\"startDate\": \"2020-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Exchange Raw Data Historic-OHLCVs","project":"Superalgos","id":"d0ff77d8-76de-4d50-840a-e50a55ad7d1b","savedPayload":{"position":{"x":23464.287287440642,"y":29377.997434862405},"targetPosition":{"x":23762.643856051123,"y":29409.355973842703},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Historic-OHLCVs","id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc"}}}],"id":"b4e33f51-f9ff-4ef3-a9b7-ccb904163cae","savedPayload":{"position":{"x":23762.643856051123,"y":29409.355973842703},"targetPosition":{"x":24061.000424661604,"y":29440.714512823},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"23ae53f9-b478-4eb4-96e7-12d07d7ae4f0","savedPayload":{"position":{"x":24061.000424661604,"y":29440.714512823},"targetPosition":{"x":24359.356993272086,"y":29472.073051803298},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Candles Volumes","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Candles Volumes","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Market","project":"Superalgos","id":"dcf3d790-5362-4a95-b977-82d0cf0e07f1","savedPayload":{"position":{"x":23646.16814072914,"y":28934.397538066118},"targetPosition":{"x":23913.47009798565,"y":29070.59468798798},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"9f683143-a33f-42c1-9fa8-c601f01ee4e1"}}},{"type":"Indicator Process Instance","name":"Candles Volumes Multi-Period-Daily","project":"Superalgos","id":"775fadbd-5b55-41b2-81ac-454f5e52dca6","savedPayload":{"position":{"x":23750.078387481142,"y":28818.993517604355},"targetPosition":{"x":23913.47009798565,"y":29070.59468798798},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"980ceb1d-7be6-454f-90d9-01ba1fd4a65d"}}}],"id":"fc478301-77ac-4396-bd3b-915b4c681fa0","savedPayload":{"position":{"x":23913.47009798565,"y":29070.59468798798},"targetPosition":{"x":24136.413545628868,"y":29271.33386989564},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"30054a4b-7c93-4a3a-a6db-2e0d38507b2e","savedPayload":{"position":{"x":24136.413545628868,"y":29271.33386989564},"targetPosition":{"x":24359.356993272086,"y":29472.073051803298},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},{"type":"Task","name":"Bollinger Bands","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"Bollinger Bands","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Bollinger Bands Multi-Period-Market","project":"Superalgos","id":"bf0f739f-98b7-4c73-ae06-8d3fe83147ce","savedPayload":{"position":{"x":24098.412828859568,"y":28617.882534106506},"targetPosition":{"x":24234.60997878143,"y":28885.184491363016},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":3,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"PLine truncated
|
||||
@@ -1 +1 @@
|
||||
{"type":"Workspace","name":"Weak-hands Buster v2","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataMining":{"type":"Data Mining","name":"New Data Mining","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Sparta","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Sparta","project":"Superalgos","tasks":[{"type":"Task","name":"EMA","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"EMA","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Exponential Moving Average (EMA) Multi-Period-Market","project":"Superalgos","id":"9adffd60-8756-44f0-9290-692711f43349","savedPayload":{"position":{"x":23470.126508730755,"y":29652.495915209296},"targetPosition":{"x":23770.126508730755,"y":29652.495915209296},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"278c34a7-199d-400e-8a06-087149e3d391"}}},{"type":"Indicator Process Instance","name":"Exponential Moving Average (EMA) Multi-Period-Daily","project":"Superalgos","id":"559fc728-018a-4e8e-a5fa-1e37958e4f6c","savedPayload":{"position":{"x":23620.126508730755,"y":29392.688294073963},"targetPosition":{"x":23770.126508730755,"y":29652.495915209296},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"943ea24f-ee24-4eae-9b4b-e8a73122b1c2"}}}],"id":"82a8c05f-a6f6-4728-8271-7b327c2b72ee","savedPayload":{"position":{"x":23770.126508730755,"y":29652.495915209296},"targetPosition":{"x":24029.934129866087,"y":29802.495915209296},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"8ae4fc50-8c1f-4e45-9ffd-fad368816b9a","savedPayload":{"position":{"x":24029.934129866087,"y":29802.495915209296},"targetPosition":{"x":24289.74175100142,"y":29952.495915209296},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}}],"id":"51b49b9d-cb97-4d98-ad8f-9f691320bac2","savedPayload":{"position":{"x":24289.74175100142,"y":29952.495915209296},"targetPosition":{"x":24549.549372136753,"y":30102.495915209296},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}}],"id":"63728769-73e4-474e-8aa3-0d82bedca08e","savedPayload":{"position":{"x":24549.549372136753,"y":30102.495915209296},"targetPosition":{"x":24809.356993272086,"y":30252.495915209296},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Data Mine","name":"Sparta","id":"9cfffc48-486a-48cb-b641-98c82e314d3a"}}},{"type":"Data Mine Tasks","name":"Masters","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Masters","project":"Superalgos","tasks":[{"type":"Task","name":"Exchange Raw Data","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Exchange Raw Data","config":"{ \n\"startDate\": \"2020-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Exchange Raw Data Historic-OHLCVs","project":"Superalgos","id":"149bc037-9762-4737-b1b8-945b5ccee230","savedPayload":{"position":{"x":24081.241698334637,"y":29123.489188146068},"targetPosition":{"x":24323.94679664712,"y":29299.82476383381},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Historic-OHLCVs","id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc"}}}],"id":"507bc325-1cbd-40f4-85eb-cfe77b78000e","savedPayload":{"position":{"x":24323.94679664712,"y":29299.82476383381},"targetPosition":{"x":24566.651894959603,"y":29476.160339521553},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"7c28a4a4-86da-43be-9e89-d01b202f27eb","savedPayload":{"position":{"x":24566.651894959603,"y":29476.160339521553},"targetPosition"Line truncated
|
||||
{"type":"Workspace","name":"Weak-hands Buster v2","rootNodes":[{"type":"Network","name":"My Network","project":"Superalgos","networkNodes":[{"type":"Network Node","name":"My Computer","config":"{ \n\"host\": \"localhost\", \n\"webPort\": \"34248\", \n\"webSocketsPort\": \"18041\"\n}","project":"Superalgos","dataTasks":{"type":"Data Tasks","name":"New Data Tasks","project":"Superalgos","projectDataTasks":[{"type":"Project Data Tasks","name":"Superalgos","project":"Superalgos","exchangeDataTasks":[{"type":"Exchange Data Tasks","name":"Binance","project":"Superalgos","marketDataTasks":[{"type":"Market Data Tasks","name":"Binance BTC/USDT","project":"Superalgos","dataMineTasks":[{"type":"Data Mine Tasks","name":"Sparta","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Sparta","project":"Superalgos","tasks":[{"type":"Task","name":"EMA","project":"Superalgos","bot":{"type":"Indicator Bot Instance","name":"EMA","config":"{}","project":"Superalgos","processes":[{"type":"Indicator Process Instance","name":"Exponential Moving Average (EMA) Multi-Period-Market","project":"Superalgos","id":"9adffd60-8756-44f0-9290-692711f43349","savedPayload":{"position":{"x":23320.126508730755,"y":29392.688294073963},"targetPosition":{"x":23620.126508730755,"y":29392.688294073963},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Market","id":"278c34a7-199d-400e-8a06-087149e3d391"}}},{"type":"Indicator Process Instance","name":"Exponential Moving Average (EMA) Multi-Period-Daily","project":"Superalgos","id":"559fc728-018a-4e8e-a5fa-1e37958e4f6c","savedPayload":{"position":{"x":23470.126508730755,"y":29132.88067293863},"targetPosition":{"x":23620.126508730755,"y":29392.688294073963},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Multi-Period-Daily","id":"943ea24f-ee24-4eae-9b4b-e8a73122b1c2"}}}],"id":"82a8c05f-a6f6-4728-8271-7b327c2b72ee","savedPayload":{"position":{"x":23620.126508730755,"y":29392.688294073963},"targetPosition":{"x":23879.934129866087,"y":29542.688294073963},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"8ae4fc50-8c1f-4e45-9ffd-fad368816b9a","savedPayload":{"position":{"x":23879.934129866087,"y":29542.688294073963},"targetPosition":{"x":24139.74175100142,"y":29692.688294073963},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}}],"id":"51b49b9d-cb97-4d98-ad8f-9f691320bac2","savedPayload":{"position":{"x":24139.74175100142,"y":29692.688294073963},"targetPosition":{"x":24399.549372136753,"y":29842.688294073963},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}}],"id":"63728769-73e4-474e-8aa3-0d82bedca08e","savedPayload":{"position":{"x":24399.549372136753,"y":29842.688294073963},"targetPosition":{"x":24659.356993272086,"y":29992.688294073963},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Data Mine","name":"Sparta","id":"9cfffc48-486a-48cb-b641-98c82e314d3a"}}},{"type":"Data Mine Tasks","name":"Masters","project":"Superalgos","taskManagers":[{"type":"Task Manager","name":"Masters","project":"Superalgos","tasks":[{"type":"Task","name":"Exchange Raw Data","project":"Superalgos","bot":{"type":"Sensor Bot Instance","name":"Exchange Raw Data","config":"{ \n\"startDate\": \"2020-01-01\"\n}","project":"Superalgos","processes":[{"type":"Sensor Process Instance","name":"Exchange Raw Data Historic-OHLCVs","project":"Superalgos","id":"149bc037-9762-4737-b1b8-945b5ccee230","savedPayload":{"position":{"x":23931.241698334637,"y":28863.681567010735},"targetPosition":{"x":24173.94679664712,"y":29040.017142698478},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false},"referenceParent":{"type":"Process Definition","name":"Historic-OHLCVs","id":"5eb11d6a-022e-4f60-97c4-d6cf90b249dc"}}}],"id":"507bc325-1cbd-40f4-85eb-cfe77b78000e","savedPayload":{"position":{"x":24173.94679664712,"y":29040.017142698478},"targetPosition":{"x":24416.651894959603,"y":29216.35271838622},"floatingObject":{"isPinned":false,"isFrozen":false,"isCollapsed":false,"angleToParent":2,"distanceToParent":3,"arrangementStyle":0},"uiObject":{"isRunning":false}}},"id":"7c28a4a4-86da-43be-9e89-d01b202f27eb","sLine truncated
|
||||
@@ -25,6 +25,12 @@
|
||||
"positionLocked": true,
|
||||
"icon": "superalgos",
|
||||
"properties": [
|
||||
{
|
||||
"name": "projectDefinition",
|
||||
"type": "node",
|
||||
"childType": "Project Definition",
|
||||
"autoAdd": true
|
||||
},
|
||||
{
|
||||
"name": "spaces",
|
||||
"type": "node",
|
||||
@@ -45,6 +51,40 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Project Definition",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Configure",
|
||||
"actionFunction": "uiObject.configEditor.activate",
|
||||
"label": "Configure",
|
||||
"iconPathOn": "configuration",
|
||||
"iconPathOff": "configuration"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"actionFunction": "payload.executeAction",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete"
|
||||
}
|
||||
],
|
||||
"initialValues": {
|
||||
"config": "{ \n \"codeName\": \"\"\n}"
|
||||
},
|
||||
"editors": {
|
||||
"config": true
|
||||
},
|
||||
"alternativeIcons": "Use Parent",
|
||||
"isTitleAllwaysVisible": false,
|
||||
"addLeftIcons": true,
|
||||
"isPinned": false,
|
||||
"level": 2,
|
||||
"propertyNameAtParent": "projectDefinition",
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Spaces",
|
||||
"menuItems": [
|
||||
@@ -146,6 +186,12 @@
|
||||
"relatedUiObject": "Tutorial",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Plugins",
|
||||
"relatedUiObject": "Plugins",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
@@ -1945,7 +1991,7 @@
|
||||
"compatibleTypes": "->Template Script->"
|
||||
},
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Dashboard->Data Mines Data->Trading Mines Data->Data Mining->Testing Environment->Production Environment->"
|
||||
"compatibleTypes": "->Dashboard->Data Mines Data->Trading Mines Data->Data Tasks->Testing Trading Tasks->Production Trading Tasks->"
|
||||
},
|
||||
"properties": []
|
||||
},
|
||||
@@ -2028,33 +2074,33 @@
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"disableIfPropertyIsDefined": true,
|
||||
"propertyToCheckFor": "dataMining",
|
||||
"label": "Add Data Mining",
|
||||
"relatedUiObject": "Data Mining",
|
||||
"propertyToCheckFor": "dataTasks",
|
||||
"label": "Add Data Tasks",
|
||||
"relatedUiObject": "Data Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"disableIfPropertyIsDefined": true,
|
||||
"propertyToCheckFor": "learningMining",
|
||||
"label": "Add Learning Mining",
|
||||
"relatedUiObject": "Learning Mining",
|
||||
"propertyToCheckFor": "learningTasks",
|
||||
"label": "Add Learning Tasks",
|
||||
"relatedUiObject": "Learning Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"disableIfPropertyIsDefined": true,
|
||||
"propertyToCheckFor": "testingEnvironment",
|
||||
"label": "Add Testing Environment",
|
||||
"relatedUiObject": "Testing Environment",
|
||||
"propertyToCheckFor": "testingTradingTasks",
|
||||
"label": "Add Testing Trading Tasks",
|
||||
"relatedUiObject": "Testing Trading Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"disableIfPropertyIsDefined": true,
|
||||
"propertyToCheckFor": "productionEnvironment",
|
||||
"label": "Add Production Environment",
|
||||
"relatedUiObject": "Production Environment",
|
||||
"propertyToCheckFor": "productionTradingTasks",
|
||||
"label": "Add Production Trading Tasks",
|
||||
"relatedUiObject": "Production Trading Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
@@ -2089,27 +2135,27 @@
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"name": "dataMining",
|
||||
"name": "dataTasks",
|
||||
"type": "node",
|
||||
"childType": "Data Mining",
|
||||
"childType": "Data Tasks",
|
||||
"autoAdd": true
|
||||
},
|
||||
{
|
||||
"name": "learningMining",
|
||||
"name": "learningTasks",
|
||||
"type": "node",
|
||||
"childType": "Learning Mining",
|
||||
"childType": "Learning Tasks",
|
||||
"autoAdd": true
|
||||
},
|
||||
{
|
||||
"name": "testingEnvironment",
|
||||
"name": "testingTradingTasks",
|
||||
"type": "node",
|
||||
"childType": "Testing Environment",
|
||||
"childType": "Testing Trading Tasks",
|
||||
"autoAdd": true
|
||||
},
|
||||
{
|
||||
"name": "productionEnvironment",
|
||||
"name": "productionTradingTasks",
|
||||
"type": "node",
|
||||
"childType": "Production Environment",
|
||||
"childType": "Production Trading Tasks",
|
||||
"autoAdd": true
|
||||
},
|
||||
{
|
||||
@@ -11838,8 +11884,7 @@
|
||||
"childType": "Dynamic Indicators",
|
||||
"autoAdd": true
|
||||
}
|
||||
],
|
||||
"propertyNameAtParent": "tradingSystem"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Trading Strategy",
|
||||
@@ -14551,17 +14596,17 @@
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Dashboard",
|
||||
"relatedUiObject": "Dashboard",
|
||||
"label": "Add Project Dashboards",
|
||||
"relatedUiObject": "Project Dashboards",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Dashboards",
|
||||
"label": "Add Missing Dashboards",
|
||||
"action": "Add Missing Project Dashboards",
|
||||
"label": "Add Missing Projects",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Dashboard",
|
||||
"relatedUiObject": "Project Dashboards",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
@@ -14596,12 +14641,59 @@
|
||||
"childType": "Space Settings",
|
||||
"autoAdd": true
|
||||
},
|
||||
{
|
||||
"name": "projectDashboards",
|
||||
"type": "array",
|
||||
"childType": "Project Dashboards"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Project Dashboards",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Dashboard",
|
||||
"relatedUiObject": "Dashboard",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Dashboards",
|
||||
"label": "Add Missing Dashboards",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Dashboard",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"propertyNameAtParent": "projectDashboards",
|
||||
"properties": [
|
||||
{
|
||||
"name": "dashboards",
|
||||
"type": "array",
|
||||
"childType": "Dashboard"
|
||||
}
|
||||
]
|
||||
],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Dashboard",
|
||||
@@ -14634,10 +14726,10 @@
|
||||
"addLeftIcons": true,
|
||||
"level": 1,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Testing Environment->Production Environment->"
|
||||
"compatibleTypes": "->Testing Trading Tasks->Production Trading Tasks->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Charting Space->"
|
||||
"compatibleTypes": "->Project Dashboards->"
|
||||
},
|
||||
"propertyNameAtParent": "dashboards",
|
||||
"properties": [
|
||||
@@ -15872,7 +15964,7 @@
|
||||
"compatibleTypes": "->Crypto Exchange->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Data Mining->"
|
||||
"compatibleTypes": "->Project Data Tasks->"
|
||||
},
|
||||
"alternativeIcons": "Use Reference Parent",
|
||||
"title": [
|
||||
@@ -15943,7 +16035,7 @@
|
||||
"compatibleTypes": "->Crypto Exchange->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Testing Environment->Production Environment->"
|
||||
"compatibleTypes": "->Project Trading Tasks->"
|
||||
},
|
||||
"alternativeIcons": "Use Reference Parent",
|
||||
"title": [
|
||||
@@ -16014,7 +16106,7 @@
|
||||
"compatibleTypes": "->Crypto Exchange->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Learning Mining->"
|
||||
"compatibleTypes": "->Project Learning Tasks->"
|
||||
},
|
||||
"alternativeIcons": "Use Reference Parent",
|
||||
"title": [
|
||||
@@ -16032,7 +16124,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Data Mining",
|
||||
"type": "Project Data Tasks",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Run All Exchange Data Tasks",
|
||||
@@ -16079,12 +16171,19 @@
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Network Node->"
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"propertyNameAtParent": "dataMining",
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Data Tasks->"
|
||||
},
|
||||
"propertyNameAtParent": "projectDataTasks",
|
||||
"properties": [
|
||||
{
|
||||
"name": "exchangeDataTasks",
|
||||
@@ -16092,10 +16191,74 @@
|
||||
"childType": "Exchange Data Tasks",
|
||||
"monitorChildrenRunning": true
|
||||
}
|
||||
],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Data Tasks",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Run All Project Data Tasks",
|
||||
"label": "Run All Project Data Tasks",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Run",
|
||||
"workDoneLabel": "Run Request Sent",
|
||||
"iconPathOn": "run",
|
||||
"iconPathOff": "run",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Stop All Project Data Tasks",
|
||||
"label": "Stop All Project Data Tasks",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Stop",
|
||||
"workDoneLabel": "Stop Request Sent",
|
||||
"iconPathOn": "stop",
|
||||
"iconPathOff": "stop",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Project Data Tasks",
|
||||
"relatedUiObject": "Project Data Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Project Data Tasks",
|
||||
"label": "Add Missing Projects",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Project Data Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Network Node->"
|
||||
},
|
||||
"propertyNameAtParent": "dataTasks",
|
||||
"properties": [
|
||||
{
|
||||
"name": "projectDataTasks",
|
||||
"type": "array",
|
||||
"childType": "Project Data Tasks",
|
||||
"monitorChildrenRunning": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Learning Mining",
|
||||
"type": "Project Learning Tasks",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Run All Exchange Learning Tasks",
|
||||
@@ -16142,12 +16305,19 @@
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Network Node->"
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"propertyNameAtParent": "learningMining",
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Learning Tasks->"
|
||||
},
|
||||
"propertyNameAtParent": "projectLearningTasks",
|
||||
"properties": [
|
||||
{
|
||||
"name": "exchangeLearningTasks",
|
||||
@@ -16155,10 +16325,74 @@
|
||||
"childType": "Exchange Learning Tasks",
|
||||
"monitorChildrenRunning": true
|
||||
}
|
||||
],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Learning Tasks",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Run All Project Learning Tasks",
|
||||
"label": "Run All Project Learning Tasks",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Run",
|
||||
"workDoneLabel": "Run Request Sent",
|
||||
"iconPathOn": "run",
|
||||
"iconPathOff": "run",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Stop All Project Learning Tasks",
|
||||
"label": "Stop All Project Learning Tasks",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Stop",
|
||||
"workDoneLabel": "Stop Request Sent",
|
||||
"iconPathOn": "stop",
|
||||
"iconPathOff": "stop",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Project Learning Tasks",
|
||||
"relatedUiObject": "Project Learning Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Project Learning Tasks",
|
||||
"label": "Add Missing Projects",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Project Learning Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Network Node->"
|
||||
},
|
||||
"propertyNameAtParent": "learningTasks",
|
||||
"properties": [
|
||||
{
|
||||
"name": "projectLearningTasks",
|
||||
"type": "array",
|
||||
"childType": "Project Learning Tasks",
|
||||
"monitorChildrenRunning": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Testing Environment",
|
||||
"type": "Project Trading Tasks",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Run All Exchange Trading Tasks",
|
||||
@@ -16205,12 +16439,19 @@
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 0,
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Network Node->"
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"propertyNameAtParent": "testingEnvironment",
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Testing Trading Tasks->Production Trading Tasks->"
|
||||
},
|
||||
"propertyNameAtParent": "projectTradingTasks",
|
||||
"properties": [
|
||||
{
|
||||
"name": "exchangeTradingTasks",
|
||||
@@ -16218,14 +16459,15 @@
|
||||
"childType": "Exchange Trading Tasks",
|
||||
"monitorChildrenRunning": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"icon": "bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Production Environment",
|
||||
"type": "Testing Trading Tasks",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Run All Exchange Trading Tasks",
|
||||
"label": "Run All Exchange Trading Tasks",
|
||||
"action": "Run All Project Trading Tasks",
|
||||
"label": "Run All Project Trading Tasks",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Run",
|
||||
"workDoneLabel": "Run Request Sent",
|
||||
@@ -16234,8 +16476,8 @@
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Stop All Exchange Trading Tasks",
|
||||
"label": "Stop All Exchange Trading Tasks",
|
||||
"action": "Stop All Project Trading Tasks",
|
||||
"label": "Stop All Project Trading Tasks",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Stop",
|
||||
"workDoneLabel": "Stop Request Sent",
|
||||
@@ -16245,17 +16487,17 @@
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Exchange Trading Tasks",
|
||||
"relatedUiObject": "Exchange Trading Tasks",
|
||||
"label": "Add Project Trading Tasks",
|
||||
"relatedUiObject": "Project Trading Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Exchange Trading Tasks",
|
||||
"label": "Add Missing Exchanges",
|
||||
"action": "Add Missing Project Trading Tasks",
|
||||
"label": "Add Missing Projects",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Exchange Trading Tasks",
|
||||
"relatedUiObject": "Project Trading Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
@@ -16273,12 +16515,75 @@
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Network Node->"
|
||||
},
|
||||
"propertyNameAtParent": "productionEnvironment",
|
||||
"propertyNameAtParent": "testingTradingTasks",
|
||||
"properties": [
|
||||
{
|
||||
"name": "exchangeTradingTasks",
|
||||
"name": "projectTradingTasks",
|
||||
"type": "array",
|
||||
"childType": "Exchange Trading Tasks",
|
||||
"childType": "Project Trading Tasks",
|
||||
"monitorChildrenRunning": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Production Trading Tasks",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Run All Project Trading Tasks",
|
||||
"label": "Run All Project Trading Tasks",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Run",
|
||||
"workDoneLabel": "Run Request Sent",
|
||||
"iconPathOn": "run",
|
||||
"iconPathOff": "run",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Stop All Project Trading Tasks",
|
||||
"label": "Stop All Project Trading Tasks",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Stop",
|
||||
"workDoneLabel": "Stop Request Sent",
|
||||
"iconPathOn": "stop",
|
||||
"iconPathOff": "stop",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Project Trading Tasks",
|
||||
"relatedUiObject": "Project Trading Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Project Trading Tasks",
|
||||
"label": "Add Missing Projects",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Project Trading Tasks",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"addLeftIcons": true,
|
||||
"level": 0,
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Network Node->"
|
||||
},
|
||||
"propertyNameAtParent": "productionTradingTasks",
|
||||
"properties": [
|
||||
{
|
||||
"name": "projectTradingTasks",
|
||||
"type": "array",
|
||||
"childType": "Project Trading Tasks",
|
||||
"monitorChildrenRunning": true
|
||||
}
|
||||
]
|
||||
@@ -16322,7 +16627,7 @@
|
||||
"compatibleTypes": "->Crypto Exchange->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Data Mines Data->"
|
||||
"compatibleTypes": "->Project Data Products->"
|
||||
},
|
||||
"propertyNameAtParent": "exchangeDataProducts",
|
||||
"properties": [
|
||||
@@ -16335,6 +16640,48 @@
|
||||
},
|
||||
{
|
||||
"type": "Data Mines Data",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Project Data Products",
|
||||
"relatedUiObject": "Project Data Products",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Project Data Products",
|
||||
"label": "Add Missing Projects",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Project Data Products",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"addLeftIcons": true,
|
||||
"level": 3,
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Data Storage->"
|
||||
},
|
||||
"propertyNameAtParent": "dataMinesData",
|
||||
"properties": [
|
||||
{
|
||||
"name": "projectDataProducts",
|
||||
"type": "array",
|
||||
"childType": "Project Data Products"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Project Data Products",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
@@ -16361,19 +16708,127 @@
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 3,
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Data Storage->"
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"propertyNameAtParent": "dataMinesData",
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Data Mines Data->"
|
||||
},
|
||||
"propertyNameAtParent": "projectDataProducts",
|
||||
"properties": [
|
||||
{
|
||||
"name": "exchangeDataProducts",
|
||||
"type": "array",
|
||||
"childType": "Exchange Data Products"
|
||||
}
|
||||
]
|
||||
],
|
||||
"icon":"bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Project Trading Products",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Exchange Trading Products",
|
||||
"relatedUiObject": "Exchange Trading Products",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Exchange Trading Products",
|
||||
"label": "Add Missing Exchanges",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Exchange Trading Products",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Trading Mines Data->"
|
||||
},
|
||||
"propertyNameAtParent": "projectTradingProducts",
|
||||
"properties": [
|
||||
{
|
||||
"name": "exchangeTradingProducts",
|
||||
"type": "array",
|
||||
"childType": "Exchange Trading Products"
|
||||
}
|
||||
],
|
||||
"icon":"bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Project Learning Products",
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Exchange Learning Products",
|
||||
"relatedUiObject": "Exchange Learning Products",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Exchange Learning Products",
|
||||
"label": "Add Missing Exchanges",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Exchange Learning Products",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete",
|
||||
"actionFunction": "payload.executeAction"
|
||||
}
|
||||
],
|
||||
"title": [
|
||||
"Use Reference Parent"
|
||||
],
|
||||
"alternativeIcons": "Use Reference Parent Parent",
|
||||
"addLeftIcons": true,
|
||||
"level": 2,
|
||||
"referenceAttachesTo": {
|
||||
"compatibleTypes": "->Project Definition->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Learning Mines Data->"
|
||||
},
|
||||
"propertyNameAtParent": "projectLearningProducts",
|
||||
"properties": [
|
||||
{
|
||||
"name": "exchangeLearningProducts",
|
||||
"type": "array",
|
||||
"childType": "Exchange Learning Products"
|
||||
}
|
||||
],
|
||||
"icon":"bitcoin"
|
||||
},
|
||||
{
|
||||
"type": "Exchange Trading Products",
|
||||
@@ -16414,7 +16869,7 @@
|
||||
"compatibleTypes": "->Crypto Exchange->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Trading Mines Data->"
|
||||
"compatibleTypes": "->Project Trading Products->"
|
||||
},
|
||||
"propertyNameAtParent": "exchangeTradingProducts",
|
||||
"properties": [
|
||||
@@ -16465,7 +16920,7 @@
|
||||
"compatibleTypes": "->Crypto Exchange->"
|
||||
},
|
||||
"chainAttachesTo": {
|
||||
"compatibleTypes": "->Learning Mines Data->"
|
||||
"compatibleTypes": "->Project Learning Products->"
|
||||
},
|
||||
"propertyNameAtParent": "exchangeLearningProducts",
|
||||
"properties": [
|
||||
@@ -16482,17 +16937,17 @@
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Exchange Trading Products",
|
||||
"relatedUiObject": "Exchange Trading Products",
|
||||
"label": "Add Project Trading Products",
|
||||
"relatedUiObject": "Project Trading Products",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Exchange Trading Products",
|
||||
"label": "Add Missing Exchanges",
|
||||
"action": "Add Missing Project Trading Products",
|
||||
"label": "Add Missing Projects",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Exchange Trading Products",
|
||||
"relatedUiObject": "Project Trading Products",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
@@ -16513,9 +16968,9 @@
|
||||
"propertyNameAtParent": "tradingMinesData",
|
||||
"properties": [
|
||||
{
|
||||
"name": "exchangeTradingProducts",
|
||||
"name": "projectTradingProducts",
|
||||
"type": "array",
|
||||
"childType": "Exchange Trading Products"
|
||||
"childType": "Project Trading Products"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -16524,17 +16979,17 @@
|
||||
"menuItems": [
|
||||
{
|
||||
"action": "Add UI Object",
|
||||
"label": "Add Exchange Learning Products",
|
||||
"relatedUiObject": "Exchange Learning Products",
|
||||
"label": "Add Project Learning Products",
|
||||
"relatedUiObject": "Project Learning Products",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Add Missing Exchange Learning Products",
|
||||
"label": "Add Missing Exchanges",
|
||||
"action": "Add Missing Project Learning Products",
|
||||
"label": "Add Missing Projects",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Proceed",
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Exchange Learning Products",
|
||||
"relatedUiObject": "Project Learning Products",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
@@ -16555,9 +17010,9 @@
|
||||
"propertyNameAtParent": "learningMinesData",
|
||||
"properties": [
|
||||
{
|
||||
"name": "exchangeLearningProducts",
|
||||
"name": "projectLearningProducts",
|
||||
"type": "array",
|
||||
"childType": "Exchange Learning Products"
|
||||
"childType": "Project Learning Products"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -17135,6 +17590,15 @@
|
||||
"workDoneLabel": "Done",
|
||||
"relatedUiObject": "Plugin Project",
|
||||
"actionFunction": "payload.executeAction"
|
||||
},
|
||||
{
|
||||
"action": "Delete UI Object",
|
||||
"askConfirmation": true,
|
||||
"confirmationLabel": "Confirm to Delete",
|
||||
"actionFunction": "payload.executeAction",
|
||||
"label": "Delete",
|
||||
"iconPathOn": "delete",
|
||||
"iconPathOff": "delete"
|
||||
}
|
||||
],
|
||||
"isHierarchyHead": true,
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"type":"Plotter Module","definition":"A plotter module is a device within a plotter that contains the definitions to create the visualization for a product definition.","content":["\r","\r","A single plotter may have several modules. Different modules may be used to plot each product of the bot, or as best suits the expected use-pattern.\r","\r","[](https://user-images.githubusercontent.com/13994516/71016077-eab41180-20f4-11ea-87e7-7262ff10a1ab.gif)\r","\r","{% include important.html content=\"For a bot to use a plotter, the corresponding product definition must establish a reference with the plotter module built to interpret the dataset.\" %}\r","\r","[](https://user-images.githubusercontent.com/13994516/71016079-eab41180-20f4-11ea-8afb-96321f9c68d8.gif)\r","\r"],"folderName":"data_mine","adding":["\r","\r","To add a plotter module, select *Add Plotter Module* on the plotter node menu.\r","\r"],"configuring":["\r","\r","Select *Configure Plotter Module* on the menu to access the configuration.\r","\r","```json\r","{\r"," \"codeName\": \"Module Name\",\r"," \"isLegacy\": true,\r"," \"icon\": \"histogram\"\r","}\r","```\r","\r","* ```codeName``` is the name used in the code to refer to the module.\r","\r","* ```isLegacy``` is ```true``` for plotters modules developed entirely in JavaScript, and is ```false``` or doesn't show in the configuration for plotters built with the tools featured in the data mine hierarchy.\r","\r","* ```icon``` is the name of the image that illustrates the corresponding layer in the Layers Panel. In case the banner is not specified, the *default banner* is used. Current possible values are:\r","\r","\r","| Value | Image|\r","| :---: | :---: |\r","| ```default``` |  |\r","| ```histogram``` |  |\r","| ```band``` |  |\r","| ```moving-average``` |  |\r","| ```oscillator``` |  |\r","| ```trend``` |  |\r","\r","Custom images may be added too. To do that:\r","\r","1. name the image in the following format: ```image-name.png```;\r","\r","1. place images in the ```WebServer\\Images\\Icons``` folder;\r","\r","1. in the configuration of the module, use the name as is (e.g.: ```\"icon\": \"image-name\"```)\r","\r"],"starting":["\r","\r","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r","\r"]},{"type":"Nodes Values"},{"type":"Nodes Highlights"},{"type":"Nodes Errors"},{"type":"Nodes Warnings"},{"type":"Nodes Infos"},{"type":"Nodes Status"},{"type":"Nodes Progress"},{"type":"Nodes Running"},{"type":"Nodes Announcements"},{"type":"Record Values"},{"type":"Shapes","definition":"The shapes node contains definitions of polygons and styles to be rendered on a per-period basis over the charts.","content":["\r","\r","A plotter recursively renders graphics for each period or candle. This means that a definition of what shapes need to be drawn for a single period is required. The plotter does the same thing for every period or candle that is visible on the screen at any point in time, for any time frame, as long as the corresponding data is available.\r","\r","[](https://user-images.githubusercontent.com/13994516/71016080-eab41180-20f4-11ea-84c6-a514b87d568f.gif)\r","\r","In general terms, the process of defining what is going to be rendered on the screen consist of the following four steps:\r","\r"," 1. Identifying points defined by ```[x,y]``` coordinates\r"," 2. Defining polygons\r"," 3. Defining default styles\r"," 4. Defining conditional styles\r","\r"],"folderName":"data_mine","adding":["\r","\r","To add a shapes node, select *Add Shapes* on the plotter module menu.\r","\r"],"configuring":["\r","\r","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r","\r"],"starting":["\r","\r","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r","\r"]},{"type":"Plotter Panel","definition":"A plotter panel usually shows numerical representations of data over the charts on a small window or panel. Line truncated
|
||||
[{"type":"Plotter Module","definition":"A plotter module is a device within a plotter that contains the definitions to create the visualization for a product definition.","content":["\r","\r","A single plotter may have several modules. Different modules may be used to plot each product of the bot, or as best suits the expected use-pattern.\r","\r","[](https://user-images.githubusercontent.com/13994516/71016077-eab41180-20f4-11ea-87e7-7262ff10a1ab.gif)\r","\r","{% include important.html content=\"For a bot to use a plotter, the corresponding product definition must establish a reference with the plotter module built to interpret the dataset.\" %}\r","\r","[](https://user-images.githubusercontent.com/13994516/71016079-eab41180-20f4-11ea-8afb-96321f9c68d8.gif)\r","\r"],"folderName":"data_mine","adding":["\r","\r","To add a plotter module, select *Add Plotter Module* on the plotter node menu.\r","\r"],"configuring":["\r","\r","Select *Configure Plotter Module* on the menu to access the configuration.\r","\r","```json\r","{\r"," \"codeName\": \"Module Name\",\r"," \"isLegacy\": true,\r"," \"icon\": \"histogram\"\r","}\r","```\r","\r","* ```codeName``` is the name used in the code to refer to the module.\r","\r","* ```isLegacy``` is ```true``` for plotters modules developed entirely in JavaScript, and is ```false``` or doesn't show in the configuration for plotters built with the tools featured in the data mine hierarchy.\r","\r","* ```icon``` is the name of the image that illustrates the corresponding layer in the Layers Panel. In case the banner is not specified, the *default banner* is used. Current possible values are:\r","\r","\r","| Value | Image|\r","| :---: | :---: |\r","| ```default``` |  |\r","| ```histogram``` |  |\r","| ```band``` |  |\r","| ```moving-average``` |  |\r","| ```oscillator``` |  |\r","| ```trend``` |  |\r","\r","Custom images may be added too. To do that:\r","\r","1. name the image in the following format: ```image-name.png```;\r","\r","1. place images in the ```WebServer\\Images\\Icons``` folder;\r","\r","1. in the configuration of the module, use the name as is (e.g.: ```\"icon\": \"image-name\"```)\r","\r"],"starting":["\r","\r","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r","\r"]},{"type":"Nodes Values"},{"type":"Nodes Highlights"},{"type":"Nodes Errors"},{"type":"Nodes Warnings"},{"type":"Nodes Infos"},{"type":"Nodes Status"},{"type":"Nodes Progress"},{"type":"Nodes Running"},{"type":"Nodes Announcements"},{"type":"Record Values"},{"type":"Shapes","definition":"The shapes node contains definitions of polygons and styles to be rendered on a per-period basis over the charts.","content":["\r","\r","A plotter recursively renders graphics for each period or candle. This means that a definition of what shapes need to be drawn for a single period is required. The plotter does the same thing for every period or candle that is visible on the screen at any point in time, for any time frame, as long as the corresponding data is available.\r","\r","[](https://user-images.githubusercontent.com/13994516/71016080-eab41180-20f4-11ea-84c6-a514b87d568f.gif)\r","\r","In general terms, the process of defining what is going to be rendered on the screen consist of the following four steps:\r","\r"," 1. Identifying points defined by ```[x,y]``` coordinates\r"," 2. Defining polygons\r"," 3. Defining default styles\r"," 4. Defining conditional styles\r","\r"],"folderName":"data_mine","adding":["\r","\r","To add a shapes node, select *Add Shapes* on the plotter module menu.\r","\r"],"configuring":["\r","\r","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r","\r"],"starting":["\r","\r","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r","\r"]},{"type":"Plotter Panel","definition":"A plotter panel usually shows numerical representations of data over the charts on a small window or panel. Line truncated
|
||||
@@ -0,0 +1,848 @@
|
||||
exports.newSuperalgosBotModulesBollingerBandsMultiPeriodDaily = function (processIndex) {
|
||||
|
||||
const MODULE_NAME = "Bollinger Bands Multi Period Daily"
|
||||
const CANDLES_FOLDER_NAME = "Candles"
|
||||
const BOLLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands"
|
||||
const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth"
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
start: start
|
||||
};
|
||||
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex);
|
||||
|
||||
let statusDependencies;
|
||||
let beginingOfMarket
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
|
||||
try {
|
||||
statusDependencies = pStatusDependencies;
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This process is going to do the following:
|
||||
Read the candles from Candles Volumes and produce daily files with bollinger bands.
|
||||
*/
|
||||
function start(callBackFunction) {
|
||||
try {
|
||||
/* Context Variables */
|
||||
let contextVariables = {
|
||||
lastBandFile: undefined, // Datetime of the last file files sucessfully produced by this process.
|
||||
firstTradeFile: undefined, // Datetime of the first trade file in the whole market history.
|
||||
maxBandFile: undefined // Datetime of the last file available to be used as an input of this process.
|
||||
};
|
||||
|
||||
let previousDay; // Holds the date of the previous day relative to the processing date.
|
||||
let processDate; // Holds the processing date.
|
||||
|
||||
getContextVariables();
|
||||
|
||||
function getContextVariables() {
|
||||
|
||||
try {
|
||||
let thisReport;
|
||||
let reportKey;
|
||||
let statusReport;
|
||||
|
||||
/* We look first for Exchange Raw Data in order to get when the market starts. */
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> reportKey = " + reportKey)
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.beginingOfMarket === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet.");
|
||||
|
||||
let customOK = {
|
||||
result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency does not exist."
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
||||
callBackFunction(customOK);
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.firstTradeFile = new Date(
|
||||
thisReport.beginingOfMarket.year + "-" +
|
||||
thisReport.beginingOfMarket.month + "-" +
|
||||
thisReport.beginingOfMarket.days + " " +
|
||||
thisReport.beginingOfMarket.hours + ":" +
|
||||
thisReport.beginingOfMarket.minutes +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
|
||||
/* Second, we get the report from Candles Volumes, to know when the marted ends. */
|
||||
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> reportKey = " + reportKey)
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
|
||||
let customOK = {
|
||||
result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency not ready."
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
||||
callBackFunction(customOK);
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.maxBandFile = new Date(thisReport.lastFile.valueOf());
|
||||
|
||||
/* Finally we get our own Status Report. */
|
||||
reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Daily"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> reportKey = " + reportKey)
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile !== undefined) {
|
||||
|
||||
beginingOfMarket = new Date(thisReport.beginingOfMarket);
|
||||
|
||||
if (beginingOfMarket.valueOf() !== contextVariables.firstTradeFile.valueOf()) { // Reset Mechanism for Begining of the Market
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Reset Mechanism for Begining of the Market Activated. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
contextVariables.lastBandFile = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
contextVariables.lastBandFile = new Date(
|
||||
contextVariables.lastBandFile.valueOf() +
|
||||
TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
buildBands();
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.lastBandFile = new Date(thisReport.lastFile);
|
||||
|
||||
/*
|
||||
The bands objects needs to be calculated over more than one day in some situations. In order to simplify the calculations we will
|
||||
always load the last 2 days of candles, and run the calculations on that array.
|
||||
|
||||
1. So first we will load the candles file of processDay -1.
|
||||
2. Secondly we will load the candles file of processDay.
|
||||
|
||||
After reading these two files we will add all candles to a unique array.
|
||||
*/
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> thisReport.lastFile !== undefined")
|
||||
|
||||
buildBands();
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
In the case when there is no status report, we take the date of the file with the first trades as the begining of the market. Then we will
|
||||
go one day further in time, so that the previous day does fine a file at the begining of the market.
|
||||
*/
|
||||
contextVariables.lastBandFile = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
contextVariables.lastBandFile = new Date(
|
||||
contextVariables.lastBandFile.valueOf() +
|
||||
TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
beginingOfMarket = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> thisReport.lastFile === undefined")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> contextVariables.lastBandFile = " + contextVariables.lastBandFile)
|
||||
|
||||
buildBands();
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> err = " + err.stack);
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ");
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
|
||||
}
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function buildBands() {
|
||||
|
||||
try {
|
||||
let n;
|
||||
processDate = new Date(contextVariables.lastBandFile.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop.
|
||||
let fromDate = new Date(processDate.valueOf())
|
||||
let lastDate = new Date()
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildBands -> processDate = " + processDate)
|
||||
|
||||
advanceTime();
|
||||
|
||||
function advanceTime() {
|
||||
|
||||
try {
|
||||
processDate = new Date(processDate.valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS);
|
||||
previousDay = new Date(processDate.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildBands -> advanceTime -> processDate = " + processDate)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildBands -> advanceTime -> previousDay = " + previousDay)
|
||||
|
||||
/* Validation that we are not going past the head of the market. */
|
||||
if (processDate.valueOf() > contextVariables.maxBandFile.valueOf()) {
|
||||
const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + ".";
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildBands -> advanceTime -> " + logText)
|
||||
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString =
|
||||
processDate.getUTCFullYear() + '-' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCMonth() + 1, 2) + '-' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCDate(), 2);
|
||||
let currentDate = new Date(processDate)
|
||||
let percentage = TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(fromDate, currentDate, lastDate)
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, currentDateString, percentage)
|
||||
|
||||
if (TS.projects.superalgos.utilities.dateTimeFunctions.areTheseDatesEqual(currentDate, new Date()) === false) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newInternalLoop(currentDate, percentage);
|
||||
}
|
||||
periodsLoop();
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> advanceTime -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function periodsLoop() {
|
||||
|
||||
try {
|
||||
/*
|
||||
We will iterate through all posible timeFrames
|
||||
*/
|
||||
n = 0 // loop Variable representing each possible period as defined at the periods array.
|
||||
loopBody();
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function loopBody() {
|
||||
|
||||
try {
|
||||
const timeFrame = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1];
|
||||
|
||||
let candles = []; // Here we will put all the candles of the 2 files read.
|
||||
|
||||
let previousDayFile;
|
||||
let processDayFile;
|
||||
|
||||
getPreviousDayFile();
|
||||
|
||||
function getPreviousDayFile() {
|
||||
try {
|
||||
let dateForPath =
|
||||
previousDay.getUTCFullYear() + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(previousDay.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(previousDay.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
let filePathRoot =
|
||||
'Project/' +
|
||||
TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" +
|
||||
"Candles-Volumes" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timeFrame + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onCurrentDayFileReceived);
|
||||
|
||||
function onCurrentDayFileReceived(err, text) {
|
||||
try {
|
||||
previousDayFile = JSON.parse(text);
|
||||
getProcessDayFile()
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> filePath = " + filePath);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getPreviousDayFile -> onCurrentDayFileReceived -> market = " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '_' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName);
|
||||
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getPreviousDayFile -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function getProcessDayFile() {
|
||||
try {
|
||||
let dateForPath =
|
||||
processDate.getUTCFullYear() + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
let filePathRoot =
|
||||
'Project/' +
|
||||
TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" +
|
||||
"Candles-Volumes" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timeFrame + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onCurrentDayFileReceived);
|
||||
|
||||
function onCurrentDayFileReceived(err, text) {
|
||||
try {
|
||||
processDayFile = JSON.parse(text);
|
||||
buildBands();
|
||||
} catch (err) {
|
||||
if (processDate.valueOf() > contextVariables.maxBandFile.valueOf()) {
|
||||
processDayFile = []; // we are past the head of the market, then no worries if this file is non existent.
|
||||
buildBands();
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> filePath = " + filePath);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getProcessDayFile -> onCurrentDayFileReceived -> market = " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '_' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName);
|
||||
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> getProcessDayFile -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function buildBands() {
|
||||
try {
|
||||
addCandlesToSingleArray(previousDayFile);
|
||||
addCandlesToSingleArray(processDayFile);
|
||||
calculateBands();
|
||||
|
||||
function addCandlesToSingleArray(candlesFile) {
|
||||
try {
|
||||
for (let i = 0; i < candlesFile.length; i++) {
|
||||
|
||||
let candle = {
|
||||
open: undefined,
|
||||
close: undefined,
|
||||
min: 10000000000000,
|
||||
max: 0,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
direction: undefined
|
||||
}
|
||||
|
||||
candle.min = candlesFile[i][0];
|
||||
candle.max = candlesFile[i][1];
|
||||
|
||||
candle.open = candlesFile[i][2];
|
||||
candle.close = candlesFile[i][3];
|
||||
|
||||
candle.begin = candlesFile[i][4];
|
||||
candle.end = candlesFile[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'; }
|
||||
|
||||
candles.push(candle);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> buildBands -> addCandlesToSingleArray -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> buildBands -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function calculateBands() {
|
||||
try {
|
||||
let bandsArray = [];
|
||||
let pBArray = [];
|
||||
let numberOfPeriodsBB = 20;
|
||||
let numberOfStandardDeviations = 2;
|
||||
let numberOfPeriodsPB = 10;
|
||||
|
||||
/* Building bands */
|
||||
let band
|
||||
|
||||
for (let i = numberOfPeriodsBB - 1; i < candles.length; i++) { // Go through all the candles to generate a band segment for each of them.
|
||||
/* Calculating the bollinger bands. */
|
||||
let movingAverage = 0;
|
||||
for (let j = i - numberOfPeriodsBB + 1; j < i + 1; j++) { // go through the last n candles to calculate the moving average.
|
||||
movingAverage = movingAverage + candles[j].close;
|
||||
}
|
||||
movingAverage = movingAverage / numberOfPeriodsBB;
|
||||
|
||||
let standardDeviation = 0;
|
||||
for (let j = i - numberOfPeriodsBB + 1; j < i + 1; j++) { // go through the last n candles to calculate the standard deviation.
|
||||
standardDeviation = standardDeviation + Math.pow(candles[j].close - movingAverage, 2);
|
||||
}
|
||||
standardDeviation = standardDeviation / numberOfPeriodsBB;
|
||||
standardDeviation = Math.sqrt(standardDeviation);
|
||||
if (standardDeviation === 0) { standardDeviation = 0.000000001; } // This is to prevent a division by zero later.
|
||||
|
||||
band = {
|
||||
begin: candles[i].begin,
|
||||
end: candles[i].end,
|
||||
movingAverage: movingAverage,
|
||||
standardDeviation: standardDeviation,
|
||||
deviation: standardDeviation * numberOfStandardDeviations
|
||||
}
|
||||
|
||||
/* Will only add to the array the bands of the current day */
|
||||
if (band.begin >= processDate.valueOf()) { bandsArray.push(band); }
|
||||
|
||||
/* Calculating %B */
|
||||
let lowerBB
|
||||
let upperBB
|
||||
|
||||
lowerBB = band.movingAverage - band.deviation;
|
||||
upperBB = band.movingAverage + band.deviation;
|
||||
|
||||
let value = (candles[i].close - lowerBB) / (upperBB - lowerBB) * 100
|
||||
|
||||
/* Moving Average Calculation */
|
||||
|
||||
let numberOfPreviousPeriods;
|
||||
let currentPosition = pBArray.length;
|
||||
|
||||
if (currentPosition < numberOfPeriodsPB) { // Avoinding to get into negative array indexes
|
||||
numberOfPreviousPeriods = currentPosition;
|
||||
} else {
|
||||
numberOfPreviousPeriods = numberOfPeriodsPB;
|
||||
}
|
||||
|
||||
movingAverage = 0
|
||||
for (let j = currentPosition - numberOfPreviousPeriods; j < currentPosition; j++) { // go through the last numberOfPeriodsPBs to calculate the moving average.
|
||||
movingAverage = movingAverage + pBArray[j].value;
|
||||
}
|
||||
movingAverage = movingAverage + value;
|
||||
movingAverage = movingAverage / (numberOfPreviousPeriods + 1);
|
||||
|
||||
let bandwidth = (upperBB - lowerBB) / band.movingAverage;
|
||||
|
||||
let percentageBandwidth = {
|
||||
begin: candles[i].begin,
|
||||
end: candles[i].end,
|
||||
value: value,
|
||||
movingAverage: movingAverage,
|
||||
bandwidth: bandwidth
|
||||
};
|
||||
|
||||
/* Will only add to the array the pBs of the current day */
|
||||
if (percentageBandwidth.begin >= processDate.valueOf()) { pBArray.push(percentageBandwidth); }
|
||||
}
|
||||
|
||||
writeBandsFile(bandsArray, pBArray);
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> calculateBands -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function writeBandsFile(pBands, pPB) {
|
||||
try {
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < pBands.length; i++) {
|
||||
|
||||
let band = pBands[i];
|
||||
|
||||
fileContent = fileContent + separator + '[' +
|
||||
band.begin + "," +
|
||||
band.end + "," +
|
||||
band.movingAverage + "," +
|
||||
band.standardDeviation + "," +
|
||||
band.deviation + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
fileRecordCounter++
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let dateForPath =
|
||||
processDate.getUTCFullYear() + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCDate(), 2);
|
||||
let fileName = 'Data.json';
|
||||
let filePath =
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT +
|
||||
"/Output/" +
|
||||
BOLLINGER_BANDS_FOLDER_NAME + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + "/" +
|
||||
timeFrame + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
try {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> writeBandBandsFile -> writeBandsFile -> onFileCreated -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
const logText = "[WARN] Finished with File @ " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "_" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName + "";
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildBands -> loopBody -> writeBandBandsFile -> writeBandsFile -> onFileCreated -> " + logText)
|
||||
|
||||
writePBFile(pPB);
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> writeBandBandsFile -> writeBandsFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> writeBandBandsFile -> writeBandsFile -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writePBFile(pPercentageBandwidths) {
|
||||
|
||||
try {
|
||||
let separator = ""
|
||||
let fileRecordCounter = 0
|
||||
|
||||
let fileContent = ""
|
||||
|
||||
for (let i = 0; i < pPercentageBandwidths.length; i++) {
|
||||
|
||||
let pB = pPercentageBandwidths[i];
|
||||
|
||||
fileContent = fileContent + separator + '[' +
|
||||
pB.begin + "," +
|
||||
pB.end + "," +
|
||||
pB.value + "," +
|
||||
pB.movingAverage + "," +
|
||||
pB.bandwidth + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
fileRecordCounter++
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let dateForPath =
|
||||
processDate.getUTCFullYear() + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCDate(), 2);
|
||||
let fileName = 'Data.json';
|
||||
let filePath =
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT +
|
||||
"/Output/" +
|
||||
PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + "/" +
|
||||
timeFrame + "/" + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
try {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> writeBandBandsFile -> writePBFile -> onFileCreated -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
const logText = "[WARN] Finished with File @ " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "_" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName + "";
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildBands -> loopBody -> writeBandBandsFile -> writePBFile -> onFileCreated -> " + logText)
|
||||
|
||||
controlLoop()
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> writeBandBandsFile -> writePBFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> writeBandBandsFile -> writePBFile -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> loopBody -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
try {
|
||||
n++
|
||||
if (n < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length) {
|
||||
loopBody()
|
||||
} else {
|
||||
n = 0
|
||||
writeDataRanges(onWritten);
|
||||
|
||||
function onWritten(err) {
|
||||
try {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> controlLoop -> onWritten -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
writeStatusReport(processDate, advanceTime);
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> controlLoop -> onWritten -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> controlLoop -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> err.message = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeDataRanges(callBack) {
|
||||
try {
|
||||
writeDataRange(contextVariables.firstTradeFile, processDate, BOLLINGER_BANDS_FOLDER_NAME, onBandsBandsDataRangeWritten);
|
||||
|
||||
function onBandsBandsDataRangeWritten(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] writeDataRanges -> writeDataRanges -> onBandsBandsDataRangeWritten -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
}
|
||||
|
||||
writeDataRange(contextVariables.firstTradeFile, processDate, PERCENTAGE_BANDWIDTH_FOLDER_NAME, onPercentageBandwidthDataRangeWritten);
|
||||
|
||||
function onPercentageBandwidthDataRangeWritten(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] writeDataRanges -> writeDataRanges -> onBandsBandsDataRangeWritten -> onPercentageBandwidthDataRangeWritten -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
}
|
||||
callBack(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeDataRanges -> err = " + err.stack)
|
||||
callBack(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function writeDataRange(pBegin, pEnd, pProductFolder, callBack) {
|
||||
try {
|
||||
let dataRange = {
|
||||
begin: pBegin.valueOf(),
|
||||
end: pEnd.valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS
|
||||
}
|
||||
|
||||
let fileContent = JSON.stringify(dataRange);
|
||||
let fileName = 'Data.Range.json';
|
||||
let filePath =
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT +
|
||||
"/Output/" +
|
||||
pProductFolder + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName;
|
||||
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
}
|
||||
|
||||
callBack(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeDataRange -> err = " + err.stack)
|
||||
callBack(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport(lastFileDate, callBack) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate)
|
||||
try {
|
||||
let reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Daily"
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
thisReport.file.lastExecution = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME;
|
||||
thisReport.file.lastFile = lastFileDate;
|
||||
thisReport.file.beginingOfMarket = beginingOfMarket.toUTCString()
|
||||
thisReport.save(callBack);
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> err.message = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,149 +1,96 @@
|
||||
exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_STORAGE) {
|
||||
exports.newSuperalgosBotModulesBollingerBandsMultiPeriodMarket = function (processIndex) {
|
||||
|
||||
const FULL_LOG = true;
|
||||
const LOG_FILE_CONTENT = false;
|
||||
|
||||
const MODULE_NAME = "User Bot";
|
||||
|
||||
const TRADES_FOLDER_NAME = "Trades";
|
||||
|
||||
const CANDLES_FOLDER_NAME = "Candles";
|
||||
const BOLLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands";
|
||||
const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth";
|
||||
const MODULE_NAME = "Bollinger Bands Multi Period Market"
|
||||
const CANDLES_FOLDER_NAME = "Candles"
|
||||
const BOLLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands"
|
||||
const PERCENTAGE_BANDWIDTH_FOLDER_NAME = "Percentage-Bandwidth"
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
start: start
|
||||
};
|
||||
|
||||
let statusDependencies;
|
||||
let utilities = UTILITIES.newCloudUtilities(bot, logger);
|
||||
let fileStorage = FILE_STORAGE.newFileStorage(logger);
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
logger.fileName = MODULE_NAME;
|
||||
logger.initialize();
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
let statusDependencies
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex)
|
||||
|
||||
This process is going to do the following:
|
||||
|
||||
Read the candles from Candles Volumes and produce the bollinger bands out of them.
|
||||
|
||||
*/
|
||||
|
||||
function start(callBackFunction) {
|
||||
return thisObject
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
try {
|
||||
statusDependencies = pStatusDependencies;
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
|
||||
|
||||
let market = bot.market;
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
/*
|
||||
This process is going to do the following:
|
||||
Read the candles from Candles Volumes and produce the bollinger bands out of them.
|
||||
*/
|
||||
function start(callBackFunction) {
|
||||
try {
|
||||
buildBands();
|
||||
|
||||
function buildBands() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> Entering function."); }
|
||||
|
||||
try {
|
||||
|
||||
let n;
|
||||
|
||||
periodsLoop();
|
||||
|
||||
let n
|
||||
periodsLoop()
|
||||
function periodsLoop() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> periodsLoop -> Entering function."); }
|
||||
|
||||
/*
|
||||
|
||||
We will iterate through all posible periods.
|
||||
|
||||
*/
|
||||
|
||||
n = 0 // loop Variable representing each possible period as defined at the periods array.
|
||||
|
||||
loopBody();
|
||||
|
||||
loopBody()
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> periodsLoop -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function loopBody() {
|
||||
|
||||
try {
|
||||
const outputPeriod = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0];
|
||||
const timeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1];
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> Entering function."); }
|
||||
|
||||
const outputPeriod = global.marketFilesPeriods[n][0];
|
||||
const timeFrame = global.marketFilesPeriods[n][1];
|
||||
|
||||
nextCandleFile();
|
||||
nextCandleFile()
|
||||
|
||||
function nextCandleFile() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> Entering function."); }
|
||||
|
||||
let fileName = "Data.json";
|
||||
|
||||
let filePathRoot = 'Project/' + bot.project + "/" + bot.mineType + "/" + bot.dataMine + "/" + "Candles-Volumes" + '/' + bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset
|
||||
let filePathRoot =
|
||||
'Project/' + TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" +
|
||||
"Candles-Volumes" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrame;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> text = " + text); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
let marketFile = JSON.parse(text);
|
||||
|
||||
let candles = [];
|
||||
|
||||
buildCandles();
|
||||
let marketFile = JSON.parse(text)
|
||||
let candles = []
|
||||
buildCandles()
|
||||
|
||||
function buildCandles() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> buildCandles -> Entering function."); }
|
||||
|
||||
try {
|
||||
|
||||
for (let i = 0; i < marketFile.length; i++) {
|
||||
|
||||
let candle = {
|
||||
@@ -166,24 +113,19 @@
|
||||
candle.end = marketFile[i][5];
|
||||
|
||||
candles.push(candle);
|
||||
|
||||
}
|
||||
|
||||
buildBands();
|
||||
|
||||
buildBands()
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> buildCandles -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> buildCandles -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function buildBands() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> buildBands -> Entering function."); }
|
||||
|
||||
let bandsArray = [];
|
||||
let pBArray = [];
|
||||
let numberOfPeriodsBB = 20;
|
||||
@@ -192,22 +134,21 @@
|
||||
|
||||
/* Building bands */
|
||||
|
||||
let band;
|
||||
let band
|
||||
|
||||
for (let i = numberOfPeriodsBB - 1; i < candles.length; i++) { // Go through all the candles to generate a band segment for each of them.
|
||||
|
||||
let movingAverage = 0;
|
||||
for (let j = i - numberOfPeriodsBB + 1; j < i + 1; j++) { // go through the last numberOfPeriodsBB candles to calculate the moving average.
|
||||
movingAverage = movingAverage + candles[j].close;
|
||||
movingAverage = movingAverage + candles[j].close
|
||||
}
|
||||
movingAverage = movingAverage / numberOfPeriodsBB;
|
||||
movingAverage = movingAverage / numberOfPeriodsBB
|
||||
|
||||
let standardDeviation = 0;
|
||||
let standardDeviation = 0
|
||||
for (let j = i - numberOfPeriodsBB + 1; j < i + 1; j++) { // go through the last numberOfPeriodsBB candles to calculate the standard deviation.
|
||||
standardDeviation = standardDeviation + Math.pow (candles[j].close - movingAverage, 2);
|
||||
standardDeviation = standardDeviation + Math.pow(candles[j].close - movingAverage, 2)
|
||||
}
|
||||
standardDeviation = standardDeviation / numberOfPeriodsBB;
|
||||
standardDeviation = Math.sqrt(standardDeviation);
|
||||
standardDeviation = standardDeviation / numberOfPeriodsBB
|
||||
standardDeviation = Math.sqrt(standardDeviation)
|
||||
if (standardDeviation === 0) { standardDeviation = 0.000000001; } // This is to prevent a division by zero later.
|
||||
|
||||
band = {
|
||||
@@ -218,20 +159,18 @@
|
||||
deviation: standardDeviation * numberOfStandardDeviations
|
||||
};
|
||||
|
||||
bandsArray.push(band);
|
||||
bandsArray.push(band)
|
||||
|
||||
/* Calculating %B */
|
||||
|
||||
let lowerBB;
|
||||
let upperBB;
|
||||
let lowerBB
|
||||
let upperBB
|
||||
|
||||
lowerBB = band.movingAverage - band.deviation;
|
||||
upperBB = band.movingAverage + band.deviation;
|
||||
|
||||
let value = (candles[i].close - lowerBB) / (upperBB - lowerBB) * 100;
|
||||
let value = (candles[i].close - lowerBB) / (upperBB - lowerBB) * 100
|
||||
|
||||
/* Moving Average Calculation */
|
||||
|
||||
let numberOfPreviousPeriods;
|
||||
let currentPosition = pBArray.length;
|
||||
|
||||
@@ -248,7 +187,7 @@
|
||||
movingAverage = movingAverage + value;
|
||||
movingAverage = movingAverage / (numberOfPreviousPeriods + 1);
|
||||
|
||||
let bandwidth = (upperBB- lowerBB) / band.movingAverage;
|
||||
let bandwidth = (upperBB - lowerBB) / band.movingAverage;
|
||||
|
||||
let percentageBandwidth = {
|
||||
begin: candles[i].begin,
|
||||
@@ -256,29 +195,25 @@
|
||||
value: value,
|
||||
movingAverage: movingAverage,
|
||||
bandwidth: bandwidth
|
||||
};
|
||||
}
|
||||
|
||||
pBArray.push(percentageBandwidth);
|
||||
pBArray.push(percentageBandwidth)
|
||||
}
|
||||
|
||||
writeBandsFile(bandsArray, pBArray);
|
||||
writeBandsFile(bandsArray, pBArray)
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> buildBands -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> buildBands -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeBandsFile(pBands, pPB) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
|
||||
let fileContent = "";
|
||||
let separator = ""
|
||||
let fileRecordCounter = 0
|
||||
let fileContent = ""
|
||||
|
||||
for (let i = 0; i < pBands.length; i++) {
|
||||
|
||||
@@ -292,63 +227,56 @@
|
||||
band.deviation + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
fileRecordCounter++;
|
||||
|
||||
fileRecordCounter++
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + BOLLINGER_BANDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrame;
|
||||
let filePath =
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT +
|
||||
"/Output/" +
|
||||
BOLLINGER_BANDS_FOLDER_NAME + "/" +
|
||||
"Multi-Period-Market" + "/" +
|
||||
timeFrame
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
try {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> fileContent = " + fileContent); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset);
|
||||
|
||||
callBackFunction(err);
|
||||
return;
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> filePath = " + filePath);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> market = " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "_" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
writePBFile(pPB);
|
||||
|
||||
writePBFile(pPB)
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function writePBFile(pPercentageBandwidths) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
|
||||
let fileContent = "";
|
||||
let separator = ""
|
||||
let fileRecordCounter = 0
|
||||
let fileContent = ""
|
||||
|
||||
for (let i = 0; i < pPercentageBandwidths.length; i++) {
|
||||
|
||||
@@ -370,126 +298,118 @@
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrame;
|
||||
let filePath =
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT +
|
||||
"/Output/" +
|
||||
PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" +
|
||||
"Multi-Period-Market" + "/" +
|
||||
timeFrame;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
try {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> onFileCreated -> Entering function."); }
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> onFileCreated -> fileContent = " + fileContent); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> onFileCreated -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> onFileCreated -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> onFileCreated -> market = " + market.baseAsset + "_" + market.quotedAsset);
|
||||
|
||||
callBackFunction(err);
|
||||
return;
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> onFileCreated -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> onFileCreated -> filePath = " + filePath);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> onFileCreated -> market = " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "_" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName);
|
||||
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
controlLoop();
|
||||
|
||||
controlLoop()
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writePBFile -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> loopBody -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> controlLoop -> Entering function."); }
|
||||
|
||||
n++;
|
||||
|
||||
if (n < global.marketFilesPeriods.length) {
|
||||
|
||||
loopBody();
|
||||
|
||||
n++
|
||||
if (n < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length) {
|
||||
loopBody()
|
||||
} else {
|
||||
|
||||
writeStatusReport(callBackFunction);
|
||||
|
||||
writeStatusReport(callBackFunction)
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> controlLoop -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> controlLoop -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildBands -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport(callBack) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); }
|
||||
|
||||
try {
|
||||
|
||||
let reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Market"
|
||||
let reportKey = "Masters" + "-" + "Bollinger-Bands" + "-" + "Multi-Period-Market"
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
thisReport.file.lastExecution = bot.processDatetime;
|
||||
thisReport.file.lastExecution = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME;
|
||||
thisReport.save(callBack);
|
||||
|
||||
if (global.areEqualDates(bot.processDatetime, new Date()) === false) {
|
||||
logger.newInternalLoop(bot.codeName, bot.process, bot.processDatetime);
|
||||
if (TS.projects.superalgos.utilities.dateTimeFunctions.areTheseDatesEqual(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME, new Date()) === false) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newInternalLoop(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME);
|
||||
}
|
||||
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString = bot.processDatetime.getUTCFullYear() + '-' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '-' + utilities.pad(bot.processDatetime.getUTCDate(), 2);
|
||||
let currentDate = new Date(bot.processDatetime)
|
||||
let currentDateString = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCDate(), 2);
|
||||
let currentDate = new Date(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME)
|
||||
let lastDate = new Date()
|
||||
bot.processHeartBeat(currentDateString, global.getPercentage(currentDate, currentDate, lastDate))
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, currentDateString, TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(currentDate, currentDate, lastDate))
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,750 @@
|
||||
exports.newSuperalgosBotModulesCandlesVolumesMultiPeriodDaily = function (processIndex) {
|
||||
|
||||
const MODULE_NAME = "Candles Volumes Multi Period Daily";
|
||||
const CANDLES_FOLDER_NAME = "Candles";
|
||||
const CANDLES_ONE_MIN = "One-Min";
|
||||
const VOLUMES_FOLDER_NAME = "Volumes";
|
||||
const VOLUMES_ONE_MIN = "One-Min";
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
start: start
|
||||
}
|
||||
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex)
|
||||
let statusDependencies;
|
||||
let beginingOfMarket
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
try {
|
||||
statusDependencies = pStatusDependencies
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> err = " + err.stack)
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
/*
|
||||
This process is going to do the following:
|
||||
Read the candles and volumes from Exchange Raw Data and produce a file for each day and for each period with candles and volumes.
|
||||
*/
|
||||
function start(callBackFunction) {
|
||||
try {
|
||||
/* Context Variables */
|
||||
let contextVariables = {
|
||||
lastCandleFile: undefined, // Datetime of the last file files sucessfully produced by this process.
|
||||
firstTradeFile: undefined, // Datetime of the first trade file in the whole market history.
|
||||
maxCandleFile: undefined // Datetime of the last file available to be used as an input of this process.
|
||||
};
|
||||
|
||||
getContextVariables();
|
||||
|
||||
function getContextVariables() {
|
||||
try {
|
||||
let thisReport;
|
||||
let reportKey;
|
||||
let statusReport;
|
||||
|
||||
/* We look first for Exchange Raw Data in order to get when the market starts. */
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> reportKey = " + reportKey)
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
if (thisReport.beginingOfMarket === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet.");
|
||||
|
||||
let customOK = {
|
||||
result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency does not exist."
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> customOK = " + customOK.message)
|
||||
callBackFunction(customOK)
|
||||
return
|
||||
}
|
||||
|
||||
contextVariables.firstTradeFile = new Date(
|
||||
thisReport.beginingOfMarket.year + "-" +
|
||||
thisReport.beginingOfMarket.month + "-" +
|
||||
thisReport.beginingOfMarket.days + " " +
|
||||
thisReport.beginingOfMarket.hours + ":" +
|
||||
thisReport.beginingOfMarket.minutes +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS)
|
||||
|
||||
/* Second, we get the report from Exchange Raw Data, to know when the marted ends. */
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> reportKey = " + reportKey)
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file
|
||||
if (thisReport.lastFile === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
|
||||
let customOK = {
|
||||
result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency not ready."
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> customOK = " + customOK.message)
|
||||
callBackFunction(customOK)
|
||||
return
|
||||
}
|
||||
|
||||
contextVariables.maxCandleFile = new Date(
|
||||
thisReport.lastFile.year + "-" +
|
||||
thisReport.lastFile.month + "-" +
|
||||
thisReport.lastFile.days + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS)
|
||||
|
||||
/* Finally we get our own Status Report. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> reportKey = " + reportKey)
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
if (thisReport.lastFile !== undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Process Running not for the very first time. -> reportKey = " + reportKey)
|
||||
|
||||
beginingOfMarket = new Date(thisReport.beginingOfMarket)
|
||||
if (beginingOfMarket.valueOf() !== contextVariables.firstTradeFile.valueOf()) { // Reset Mechanism for Begining of the Market
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Reset Mechanism for Begining of the Market Activated. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS)
|
||||
contextVariables.lastCandleFile = new Date(
|
||||
contextVariables.lastCandleFile.valueOf() -
|
||||
TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) // Go back one day to start well.
|
||||
|
||||
buildCandles()
|
||||
return
|
||||
}
|
||||
|
||||
contextVariables.lastCandleFile = new Date(thisReport.lastFile);
|
||||
/*
|
||||
Here we assume that the last day written might contain incomplete information. This actually happens every time the head of the market is reached.
|
||||
For that reason we go back one day, the partial information is discarded and added again with whatever new info is available.
|
||||
*/
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
buildCandles()
|
||||
return
|
||||
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Process Running for the very first time. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS)
|
||||
contextVariables.lastCandleFile = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS)
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS); // Go back one day to start well.
|
||||
|
||||
buildCandles()
|
||||
return
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> err = " + err.stack)
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ");
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys))
|
||||
}
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function buildCandles() {
|
||||
try {
|
||||
let fromDate = new Date(contextVariables.lastCandleFile.valueOf())
|
||||
let lastDate = new Date()
|
||||
let outputCandles
|
||||
let outputVolumes
|
||||
|
||||
advanceTime()
|
||||
|
||||
function advanceTime() {
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> advanceTime -> New processing time @ " + contextVariables.lastCandleFile.getUTCFullYear() + "/" + (contextVariables.lastCandleFile.getUTCMonth() + 1) + "/" + contextVariables.lastCandleFile.getUTCDate() + ".")
|
||||
|
||||
/* Validation that we are not going past the head of the market. */
|
||||
if (contextVariables.lastCandleFile.valueOf() > contextVariables.maxCandleFile.valueOf()) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> advanceTime -> Head of the market found @ " + contextVariables.lastCandleFile.getUTCFullYear() + "/" + (contextVariables.lastCandleFile.getUTCMonth() + 1) + "/" + contextVariables.lastCandleFile.getUTCDate() + ".")
|
||||
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE) // Here is where we finish processing and wait for the platform to run this module again.
|
||||
return
|
||||
}
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString =
|
||||
contextVariables.lastCandleFile.getUTCFullYear() + '-' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '-' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCDate(), 2)
|
||||
let currentDate = new Date(contextVariables.lastCandleFile)
|
||||
let percentage = TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(fromDate, currentDate, lastDate)
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, currentDateString, percentage)
|
||||
|
||||
if (TS.projects.superalgos.utilities.dateTimeFunctions.areTheseDatesEqual(currentDate, new Date()) === false) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newInternalLoop(currentDate, percentage);
|
||||
}
|
||||
/*
|
||||
We prepere the arrays that will accumulate all the information for each output file.
|
||||
*/
|
||||
outputCandles = []
|
||||
outputVolumes = []
|
||||
|
||||
for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; n++) {
|
||||
const emptyArray1 = []
|
||||
const emptyArray2 = []
|
||||
outputCandles.push(emptyArray1)
|
||||
outputVolumes.push(emptyArray2)
|
||||
}
|
||||
periodsLoop();
|
||||
}
|
||||
|
||||
function periodsLoop() {
|
||||
/*
|
||||
We will iterate through all posible periods.
|
||||
*/
|
||||
let n = 0 // loop Variable representing each possible period as defined at the periods array.
|
||||
loopBody();
|
||||
|
||||
function loopBody() {
|
||||
const outputPeriod = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][0]
|
||||
const timeFrame = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]
|
||||
|
||||
nextCandleFile();
|
||||
|
||||
function nextCandleFile() {
|
||||
let dateForPath =
|
||||
contextVariables.lastCandleFile.getUTCFullYear() + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCDate(), 2)
|
||||
let fileName = "Data.json"
|
||||
|
||||
let filePathRoot =
|
||||
'Project/' +
|
||||
TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" +
|
||||
"Exchange-Raw-Data" + '/' +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + CANDLES_ONE_MIN + '/' + dateForPath
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived)
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> periodsLoop -> loopBody -> getting file at dateForPath = " + dateForPath)
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
try {
|
||||
let candlesFile;
|
||||
|
||||
if (err.result === TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
candlesFile = JSON.parse(text);
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Error Parsing JSON -> err = " + err.stack)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (err.message === 'File does not exist.' || err.code === 'The specified key does not exist.') {
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Dependency Not Ready -> err = " + err.stack)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Error Received -> err = " + err.stack)
|
||||
callBackFunction(err);
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const inputCandlesPerdiod = 60 * 1000; // 1 min
|
||||
const inputFilePeriod = 24 * 60 * 60 * 1000; // 24 hs
|
||||
|
||||
let totalOutputCandles = inputFilePeriod / outputPeriod;
|
||||
let beginingOutputTime = contextVariables.lastCandleFile.valueOf();
|
||||
|
||||
for (let i = 0; i < totalOutputCandles; i++) {
|
||||
|
||||
let outputCandle = {
|
||||
open: 0,
|
||||
close: 0,
|
||||
min: 0,
|
||||
max: 0,
|
||||
begin: 0,
|
||||
end: 0
|
||||
}
|
||||
|
||||
let saveCandle = false;
|
||||
|
||||
outputCandle.begin = beginingOutputTime + i * outputPeriod;
|
||||
outputCandle.end = beginingOutputTime + (i + 1) * outputPeriod - 1;
|
||||
|
||||
for (let j = 0; j < candlesFile.length; j++) {
|
||||
|
||||
let candle = {
|
||||
open: candlesFile[j][2],
|
||||
close: candlesFile[j][3],
|
||||
min: candlesFile[j][0],
|
||||
max: candlesFile[j][1],
|
||||
begin: candlesFile[j][4],
|
||||
end: candlesFile[j][5]
|
||||
};
|
||||
|
||||
/* Here we discard all the candles out of range. */
|
||||
if (candle.begin >= outputCandle.begin && candle.end <= outputCandle.end) {
|
||||
|
||||
if (saveCandle === false) { // this will set the value only once.
|
||||
outputCandle.open = candle.open;
|
||||
outputCandle.min = candle.min
|
||||
outputCandle.max = candle.max
|
||||
}
|
||||
|
||||
saveCandle = true;
|
||||
outputCandle.close = candle.close; // only the last one will be saved
|
||||
if (candle.min < outputCandle.min) {
|
||||
outputCandle.min = candle.min
|
||||
}
|
||||
if (candle.max > outputCandle.max) {
|
||||
outputCandle.max = candle.max
|
||||
}
|
||||
}
|
||||
}
|
||||
if (saveCandle === true) { // then we have a valid candle, otherwise it means there were no candles to fill this one in its time range.
|
||||
outputCandles[n].push(outputCandle)
|
||||
}
|
||||
}
|
||||
nextVolumeFile();
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function nextVolumeFile() {
|
||||
try {
|
||||
let dateForPath = contextVariables.lastCandleFile.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
let filePathRoot =
|
||||
'Project/' +
|
||||
TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" +
|
||||
"Exchange-Raw-Data" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let filePath =
|
||||
filePathRoot +
|
||||
"/Output/" +
|
||||
VOLUMES_FOLDER_NAME + '/' +
|
||||
VOLUMES_ONE_MIN + '/' +
|
||||
dateForPath
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> getting file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
let volumesFile
|
||||
|
||||
if (err.result === TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
volumesFile = JSON.parse(text);
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Error Parsing JSON -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Error Received -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
const inputVolumesPerdiod = 60 * 1000; // 1 min
|
||||
const inputFilePeriod = 24 * 60 * 60 * 1000; // 24 hs
|
||||
let totalOutputVolumes = inputFilePeriod / outputPeriod; // this should be 2 in this case.
|
||||
let beginingOutputTime = contextVariables.lastCandleFile.valueOf();
|
||||
|
||||
for (let i = 0; i < totalOutputVolumes; i++) {
|
||||
let outputVolume = {
|
||||
buy: 0,
|
||||
sell: 0,
|
||||
begin: 0,
|
||||
end: 0
|
||||
}
|
||||
let saveVolume = false;
|
||||
|
||||
outputVolume.begin = beginingOutputTime + i * outputPeriod;
|
||||
outputVolume.end = beginingOutputTime + (i + 1) * outputPeriod - 1;
|
||||
|
||||
for (let j = 0; j < volumesFile.length; j++) {
|
||||
let volume = {
|
||||
buy: volumesFile[j][0],
|
||||
sell: volumesFile[j][1],
|
||||
begin: volumesFile[j][2],
|
||||
end: volumesFile[j][3]
|
||||
}
|
||||
|
||||
/* Here we discard all the Volumes out of range. */
|
||||
if (volume.begin >= outputVolume.begin && volume.end <= outputVolume.end) {
|
||||
saveVolume = true
|
||||
outputVolume.buy = outputVolume.buy + volume.buy
|
||||
outputVolume.sell = outputVolume.sell + volume.sell
|
||||
}
|
||||
}
|
||||
|
||||
if (saveVolume === true) {
|
||||
outputVolumes[n].push(outputVolume);
|
||||
}
|
||||
}
|
||||
writeFiles(outputCandles[n], outputVolumes[n], timeFrame, controlLoop)
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
n++;
|
||||
if (n < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length) {
|
||||
loopBody()
|
||||
} else {
|
||||
writeDataRanges(onWritten);
|
||||
|
||||
function onWritten(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] writeDataRanges -> writeDataRanges -> onCandlesDataRangeWritten -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
}
|
||||
writeStatusReport(contextVariables.lastCandleFile, advanceTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeFiles(candles, volumes, timeFrame, callBack) {
|
||||
/*
|
||||
Here we will write the contents of the Candles and Volumens files.
|
||||
*/
|
||||
try {
|
||||
writeCandles()
|
||||
|
||||
function writeCandles() {
|
||||
let separator = ""
|
||||
let fileRecordCounter = 0
|
||||
let fileContent = ""
|
||||
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
let candle = candles[i]
|
||||
fileContent = fileContent + separator + '[' + candles[i].min + "," + candles[i].max + "," + candles[i].open + "," + candles[i].close + "," + candles[i].begin + "," + candles[i].end + "]";
|
||||
if (separator === "") { separator = ","; }
|
||||
fileRecordCounter++
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let dateForPath =
|
||||
contextVariables.lastCandleFile.getUTCFullYear() + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCDate(), 2)
|
||||
let filePath =
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT +
|
||||
"/Output/" +
|
||||
CANDLES_FOLDER_NAME + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + "/" +
|
||||
timeFrame + "/" +
|
||||
dateForPath
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated)
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> writeFiles -> writeCandles -> creating file at filePath = " + filePath);
|
||||
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeFiles -> writeCandles -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> writeFiles -> writeCandles -> onFileCreated -> Finished with File @ " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "_" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName);
|
||||
|
||||
writeVolumes();
|
||||
}
|
||||
}
|
||||
|
||||
function writeVolumes() {
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < volumes.length; i++) {
|
||||
let candle = volumes[i];
|
||||
fileContent = fileContent + separator + '[' + volumes[i].buy + "," + volumes[i].sell + "," + volumes[i].begin + "," + volumes[i].end + "]";
|
||||
if (separator === "") { separator = ","; }
|
||||
fileRecordCounter++
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let dateForPath =
|
||||
contextVariables.lastCandleFile.getUTCFullYear() + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCDate(), 2)
|
||||
let filePath =
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT +
|
||||
"/Output/" +
|
||||
VOLUMES_FOLDER_NAME + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + "/" +
|
||||
timeFrame + "/" + dateForPath
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> writeFiles -> writeVolumes -> creating file at filePath = " + filePath);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeFiles -> writeVolumes -> onFileCreated -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> writeFiles -> writeVolumes -> onFileCreated -> Finished with File @ " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "_" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName);
|
||||
|
||||
callBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeFiles -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeDataRanges(callBack) {
|
||||
try {
|
||||
writeDataRange(contextVariables.firstTradeFile, contextVariables.lastCandleFile, CANDLES_FOLDER_NAME, onCandlesDataRangeWritten);
|
||||
|
||||
function onCandlesDataRangeWritten(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] writeDataRanges -> writeDataRanges -> onCandlesDataRangeWritten -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
}
|
||||
|
||||
writeDataRange(contextVariables.firstTradeFile, contextVariables.lastCandleFile, VOLUMES_FOLDER_NAME, onVolumeDataRangeWritten);
|
||||
|
||||
function onVolumeDataRangeWritten(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] writeDataRanges -> writeDataRanges -> onVolumeDataRangeWritten -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
}
|
||||
callBack(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeDataRanges -> err = " + err.stack);
|
||||
callBack(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function writeDataRange(pBegin, pEnd, pProductFolder, callBack) {
|
||||
try {
|
||||
let dataRange = {
|
||||
begin: pBegin.valueOf(),
|
||||
end: pEnd.valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS
|
||||
}
|
||||
|
||||
let fileContent = JSON.stringify(dataRange);
|
||||
|
||||
let fileName = 'Data.Range.json';
|
||||
let filePath =
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + pProductFolder + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
}
|
||||
|
||||
let key =
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" +
|
||||
pProductFolder + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let event = {
|
||||
dateRange: dataRange
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.raiseEvent(key, 'Data Range Updated', event)
|
||||
|
||||
callBack(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeDataRange -> err = " + err.stack)
|
||||
callBack(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport(lastFileDate, callBack) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate)
|
||||
try {
|
||||
let reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Daily"
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
thisReport.file.lastExecution = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME;
|
||||
thisReport.file.lastFile = lastFileDate;
|
||||
thisReport.file.beginingOfMarket = beginingOfMarket.toUTCString()
|
||||
thisReport.save(callBack);
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] 'Start' - ERROR : " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,880 @@
|
||||
exports.newSuperalgosBotModulesCandlesVolumesMultiPeriodMarket = function (processIndex) {
|
||||
|
||||
const MODULE_NAME = "Candles Volumes Multi Period Market"
|
||||
const CANDLES_FOLDER_NAME = "Candles"
|
||||
const CANDLES_ONE_MIN = "One-Min"
|
||||
const VOLUMES_FOLDER_NAME = "Volumes"
|
||||
const VOLUMES_ONE_MIN = "One-Min"
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
start: start
|
||||
}
|
||||
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex);
|
||||
let statusDependencies;
|
||||
let beginingOfMarket
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
try {
|
||||
statusDependencies = pStatusDependencies;
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This process is going to do the following:
|
||||
|
||||
Read the candles and volumes from Exchange Raw Data and produce a single Index File for Market Period. But this is the situation:
|
||||
|
||||
Exchange Raw Data has a dataset organized with daily files with candles of 1 min. Candles Volumes is writting in this process a single file for each timeFrame for the whole market.
|
||||
Everytime this process run, must be able to resume its job and process everything pending until reaching the head of the market. So the tactic to do this is the
|
||||
following:
|
||||
|
||||
1. First we need to read the last file written by this process, and load all the information into in-memory arrays. We will then append to this arrays the new
|
||||
information we will get from Exchange Raw Data.
|
||||
|
||||
2. We know from out status report which was the last DAY we processed from Exchange Raw Data, but we must be carefull, because that day mightn not have been complete, if the
|
||||
last run found the head of the market. That means that we have to be carefull not to append candles that are already there. To simplify what we do is to discard
|
||||
all candles of the last processed day, and then we can process that full day again adding all the candles.
|
||||
*/
|
||||
|
||||
function start(callBackFunction) {
|
||||
|
||||
try {
|
||||
/* Context Variables */
|
||||
let contextVariables = {
|
||||
lastCandleFile: undefined, // Datetime of the last file files sucessfully produced by this process.
|
||||
firstTradeFile: undefined, // Datetime of the first trade file in the whole market history.
|
||||
maxCandleFile: undefined // Datetime of the last file available to be used as an input of this process.
|
||||
};
|
||||
|
||||
getContextVariables();
|
||||
|
||||
function getContextVariables() {
|
||||
try {
|
||||
let thisReport;
|
||||
let reportKey;
|
||||
let statusReport;
|
||||
|
||||
/* We look first for Exchange Raw Data in order to get when the market starts. */
|
||||
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> reportKey = " + reportKey)
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.beginingOfMarket === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet.");
|
||||
|
||||
let customOK = {
|
||||
result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency does not exist."
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
||||
callBackFunction(customOK)
|
||||
return
|
||||
}
|
||||
|
||||
contextVariables.firstTradeFile = new Date(
|
||||
thisReport.beginingOfMarket.year + "-" +
|
||||
thisReport.beginingOfMarket.month + "-" +
|
||||
thisReport.beginingOfMarket.days + " " +
|
||||
thisReport.beginingOfMarket.hours + ":" +
|
||||
thisReport.beginingOfMarket.minutes +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
|
||||
/* Second, we get the report from Exchange Raw Data, to know when the marted ends. */
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> reportKey = " + reportKey)
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
||||
|
||||
let customOK = {
|
||||
result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency not ready."
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
||||
callBackFunction(customOK);
|
||||
return;
|
||||
}
|
||||
|
||||
contextVariables.maxCandleFile = new Date(
|
||||
thisReport.lastFile.year + "-" +
|
||||
thisReport.lastFile.month + "-" +
|
||||
thisReport.lastFile.days + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
|
||||
/* Finally we get our own Status Report. */
|
||||
reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Market"
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> reportKey = " + reportKey)
|
||||
|
||||
statusReport = statusDependencies.statusReports.get(reportKey);
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
return
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile !== undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Process Running not for the very first time. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(thisReport.beginingOfMarket);
|
||||
|
||||
if (beginingOfMarket.valueOf() !== contextVariables.firstTradeFile.valueOf()) { // Reset Mechanism for Begining of the Market
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Reset Mechanism for Begining of the Market Activated. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(
|
||||
contextVariables.lastCandleFile.valueOf() -
|
||||
TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS); // Go back one day to start well.
|
||||
|
||||
buildCandles()
|
||||
return
|
||||
}
|
||||
|
||||
contextVariables.lastCandleFile = new Date(thisReport.lastFile);
|
||||
|
||||
/*
|
||||
Here we assume that the last day written might contain incomplete information. This actually happens every time the head of the market is reached.
|
||||
For that reason we go back one day, the partial information is discarded and added again with whatever new info is available.
|
||||
*/
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
findPreviousContent()
|
||||
return
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Process Running for the very first time. -> reportKey = " + reportKey);
|
||||
|
||||
beginingOfMarket = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(
|
||||
contextVariables.firstTradeFile.getUTCFullYear() + "-" +
|
||||
(contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
contextVariables.lastCandleFile = new Date(
|
||||
contextVariables.lastCandleFile.valueOf() -
|
||||
TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS); // Go back one day to start well.
|
||||
|
||||
buildCandles()
|
||||
return
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> err = " + err.stack);
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ");
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Dependencies loaded -> Double check that you are not running a process that only can be run at noTime mode at a certain month when it is not prepared to do so.");
|
||||
}
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function findPreviousContent() {
|
||||
/*
|
||||
This is where we read the current files we have produced at previous runs of this same process. We just read all the content and organize it
|
||||
in arrays and keep them in memory.
|
||||
*/
|
||||
try {
|
||||
let n = 0 // loop Variable representing each possible period as defined at the periods array.
|
||||
|
||||
let allPreviousCandles = [];
|
||||
let allPreviousVolumes = [];
|
||||
|
||||
loopBody()
|
||||
|
||||
function loopBody() {
|
||||
let timeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1];
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> findPreviousContent -> loopBody -> timeFrame = " + timeFrame)
|
||||
|
||||
let previousCandles
|
||||
let previousVolumes
|
||||
|
||||
getCandles()
|
||||
|
||||
function getCandles() {
|
||||
let fileName = 'Data.json';
|
||||
let filePath =
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT +
|
||||
"/Output/" +
|
||||
CANDLES_FOLDER_NAME + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + "/" +
|
||||
timeFrame;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> findPreviousContent -> loopBody -> getCandles -> getting file.");
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
let candlesFile
|
||||
|
||||
if (err.result === TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
candlesFile = JSON.parse(text);
|
||||
previousCandles = candlesFile;
|
||||
getVolumes();
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> fileName = " + fileName);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> filePath = " + filePath);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
}
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> loopBody -> getCandles -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getVolumes() {
|
||||
let fileName = 'Data.json';
|
||||
let filePath =
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT +
|
||||
"/Output/" +
|
||||
VOLUMES_FOLDER_NAME + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + "/" +
|
||||
timeFrame;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> findPreviousContent -> loopBody -> getVolumes -> getting file.");
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
let volumesFile
|
||||
|
||||
if (err.result === TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
volumesFile = JSON.parse(text);
|
||||
previousVolumes = volumesFile;
|
||||
allPreviousCandles.push(previousCandles);
|
||||
allPreviousVolumes.push(previousVolumes);
|
||||
|
||||
controlLoop();
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> fileName = " + fileName);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> filePath = " + filePath);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
}
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> loopBody -> getVolumes -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
n++
|
||||
if (n < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length) {
|
||||
loopBody()
|
||||
} else {
|
||||
buildCandles(allPreviousCandles, allPreviousVolumes);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> findPreviousContent -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function buildCandles(allPreviousCandles, allPreviousVolumes) {
|
||||
|
||||
try {
|
||||
let fromDate = new Date(contextVariables.lastCandleFile.valueOf())
|
||||
let lastDate = new Date()
|
||||
/*
|
||||
Firstly we prepere the arrays that will accumulate all the information for each output file.
|
||||
*/
|
||||
let outputCandles = [];
|
||||
let outputVolumes = [];
|
||||
|
||||
for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; n++) {
|
||||
const emptyArray1 = [];
|
||||
const emptyArray2 = [];
|
||||
outputCandles.push(emptyArray1);
|
||||
outputVolumes.push(emptyArray2);
|
||||
}
|
||||
|
||||
advanceTime()
|
||||
|
||||
function advanceTime() {
|
||||
contextVariables.lastCandleFile = new Date(contextVariables.lastCandleFile.valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> advanceTime -> New processing time @ " + contextVariables.lastCandleFile.getUTCFullYear() + "/" + (contextVariables.lastCandleFile.getUTCMonth() + 1) + "/" + contextVariables.lastCandleFile.getUTCDate() + ".")
|
||||
|
||||
/* Validation that we are not going past the head of the market. */
|
||||
if (contextVariables.lastCandleFile.valueOf() > contextVariables.maxCandleFile.valueOf()) {
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> advanceTime -> Head of the market found @ " + contextVariables.lastCandleFile.getUTCFullYear() + "/" + (contextVariables.lastCandleFile.getUTCMonth() + 1) + "/" + contextVariables.lastCandleFile.getUTCDate() + ".")
|
||||
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE); // Here is where we finish processing and wait for the platform to run this module again.
|
||||
return
|
||||
}
|
||||
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString =
|
||||
contextVariables.lastCandleFile.getUTCFullYear() + '-' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '-' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let currentDate = new Date(contextVariables.lastCandleFile)
|
||||
let percentage = TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(fromDate, currentDate, lastDate)
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, currentDateString, percentage)
|
||||
|
||||
if (TS.projects.superalgos.utilities.dateTimeFunctions.areTheseDatesEqual(currentDate, new Date()) === false) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newInternalLoop(currentDate, percentage);
|
||||
}
|
||||
periodsLoop()
|
||||
}
|
||||
|
||||
function periodsLoop() {
|
||||
/*
|
||||
We will iterate through all posible periods.
|
||||
*/
|
||||
let n = 0 // loop Variable representing each possible period as defined at the periods array.
|
||||
|
||||
loopBody()
|
||||
|
||||
function loopBody() {
|
||||
let previousCandles
|
||||
let previousVolumes
|
||||
if (allPreviousCandles !== undefined) {
|
||||
previousCandles = allPreviousCandles[n];
|
||||
previousVolumes = allPreviousVolumes[n];
|
||||
}
|
||||
|
||||
const outputPeriod = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0];
|
||||
const timeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1];
|
||||
/*
|
||||
Here we are inside a Loop that is going to advance 1 day at the time, at each pass, will ready one of Exchange Raw Data's daily files and
|
||||
add all its candles to our in memory arrays. At the first iteration of this loop, we will add the candles that we are carrying
|
||||
from our previous run, the ones we already have in-memory. You can see below how we discard from those candles the ones that
|
||||
are belonging to the first day we are processing at this run, that it is exactly the same as the last day processed the privious
|
||||
run. By discarding these candles, we are ready to run after that standard function that will just add ALL the candles found each
|
||||
day at Exchange Raw Data.
|
||||
*/
|
||||
|
||||
if (previousCandles !== undefined) {
|
||||
for (let i = 0; i < previousCandles.length; i++) {
|
||||
let candle = {
|
||||
open: previousCandles[i][2],
|
||||
close: previousCandles[i][3],
|
||||
min: previousCandles[i][0],
|
||||
max: previousCandles[i][1],
|
||||
begin: previousCandles[i][4],
|
||||
end: previousCandles[i][5]
|
||||
}
|
||||
|
||||
if (candle.end < contextVariables.lastCandleFile.valueOf()) {
|
||||
outputCandles[n].push(candle);
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> periodsLoop -> loopBody -> Candle # " + i + " @ " + timeFrame + " discarded for closing past the current process time.")
|
||||
}
|
||||
}
|
||||
allPreviousCandles[n] = [] // erasing these so as not to duplicate them.
|
||||
}
|
||||
|
||||
if (previousVolumes !== undefined) {
|
||||
|
||||
for (let i = 0; i < previousVolumes.length; i++) {
|
||||
let volume = {
|
||||
begin: previousVolumes[i][2],
|
||||
end: previousVolumes[i][3],
|
||||
buy: previousVolumes[i][0],
|
||||
sell: previousVolumes[i][1]
|
||||
}
|
||||
|
||||
if (volume.end < contextVariables.lastCandleFile.valueOf()) {
|
||||
|
||||
outputVolumes[n].push(volume);
|
||||
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> periodsLoop -> loopBody -> Volume # " + i + " @ " + timeFrame + " discarded for closing past the current process time.")
|
||||
}
|
||||
}
|
||||
allPreviousVolumes[n] = []; // erasing these so as not to duplicate them.
|
||||
}
|
||||
/*
|
||||
From here on is where every iteration of the loop fully runs. Here is where we read Exchange Raw Data's files and add their content to whatever
|
||||
we already have in our arrays in-memory. In this way the process will run as many days needed and it should only stop when it reaches
|
||||
the head of the market.
|
||||
*/
|
||||
nextCandleFile();
|
||||
|
||||
function nextCandleFile() {
|
||||
let dateForPath = contextVariables.lastCandleFile.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
|
||||
let filePathRoot =
|
||||
'Project/' +
|
||||
TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" +
|
||||
"Exchange-Raw-Data" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + CANDLES_ONE_MIN + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> getting file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
try {
|
||||
let candlesFile
|
||||
|
||||
if (err.result === TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
candlesFile = JSON.parse(text);
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Error Parsing JSON -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
||||
if (err.message === 'File does not exist.' || err.code === 'The specified key does not exist.') {
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Dependency Not Ready -> err = " + JSON.stringify(err));
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return
|
||||
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> Error Received -> err = " + err.stack);
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const inputCandlesPerdiod = 60 * 1000; // 1 min
|
||||
const inputFilePeriod = 24 * 60 * 60 * 1000; // 24 hs
|
||||
let totalOutputCandles = inputFilePeriod / outputPeriod; // this should be 2 in this case.
|
||||
let beginingOutputTime = contextVariables.lastCandleFile.valueOf();
|
||||
/*
|
||||
The algorithm that follows is going to agregate candles of 1 min timeFrame read from Exchange Raw Data, into candles of each timeFrame
|
||||
that Candles Volumes generates. For market files those timePediods goes from 1h to 24hs.
|
||||
*/
|
||||
for (let i = 0; i < totalOutputCandles; i++) {
|
||||
|
||||
let outputCandle = {
|
||||
open: 0,
|
||||
close: 0,
|
||||
min: 0,
|
||||
max: 0,
|
||||
begin: 0,
|
||||
end: 0
|
||||
};
|
||||
|
||||
let saveCandle = false;
|
||||
outputCandle.begin = beginingOutputTime + i * outputPeriod;
|
||||
outputCandle.end = beginingOutputTime + (i + 1) * outputPeriod - 1;
|
||||
|
||||
for (let j = 0; j < candlesFile.length; j++) {
|
||||
let candle = {
|
||||
open: candlesFile[j][2],
|
||||
close: candlesFile[j][3],
|
||||
min: candlesFile[j][0],
|
||||
max: candlesFile[j][1],
|
||||
begin: candlesFile[j][4],
|
||||
end: candlesFile[j][5]
|
||||
}
|
||||
/* Here we discard all the candles out of range. */
|
||||
if (candle.begin >= outputCandle.begin && candle.end <= outputCandle.end) {
|
||||
|
||||
if (saveCandle === false) { // this will set the value only once.
|
||||
outputCandle.open = candle.open;
|
||||
outputCandle.min = candle.min;
|
||||
outputCandle.max = candle.max;
|
||||
}
|
||||
|
||||
saveCandle = true;
|
||||
outputCandle.close = candle.close; // only the last one will be saved
|
||||
if (candle.min < outputCandle.min) {
|
||||
outputCandle.min = candle.min;
|
||||
}
|
||||
if (candle.max > outputCandle.max) {
|
||||
outputCandle.max = candle.max;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (saveCandle === true) { // then we have a valid candle, otherwise it means there were no candles to fill this one in its time range.
|
||||
outputCandles[n].push(outputCandle);
|
||||
}
|
||||
}
|
||||
nextVolumeFile();
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function nextVolumeFile() {
|
||||
try {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> Entering function.")
|
||||
|
||||
let dateForPath =
|
||||
contextVariables.lastCandleFile.getUTCFullYear() + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(contextVariables.lastCandleFile.getUTCDate(), 2);
|
||||
let fileName = "Data.json"
|
||||
|
||||
let filePathRoot =
|
||||
'Project/' +
|
||||
TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" +
|
||||
"Exchange-Raw-Data" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let filePath = filePathRoot + "/Output/" + VOLUMES_FOLDER_NAME + '/' + VOLUMES_ONE_MIN + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> getting file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Entering function.")
|
||||
|
||||
let volumesFile
|
||||
if (err.result === TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
try {
|
||||
volumesFile = JSON.parse(text);
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Error Parsing JSON -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> Error Received -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
const inputVolumesPerdiod = 60 * 1000; // 1 min
|
||||
const inputFilePeriod = 24 * 60 * 60 * 1000; // 24 hs
|
||||
|
||||
let totalOutputVolumes = inputFilePeriod / outputPeriod; // this should be 2 in this case.
|
||||
let beginingOutputTime = contextVariables.lastCandleFile.valueOf();
|
||||
|
||||
for (let i = 0; i < totalOutputVolumes; i++) {
|
||||
let outputVolume = {
|
||||
buy: 0,
|
||||
sell: 0,
|
||||
begin: 0,
|
||||
end: 0
|
||||
}
|
||||
|
||||
let saveVolume = false;
|
||||
outputVolume.begin = beginingOutputTime + i * outputPeriod;
|
||||
outputVolume.end = beginingOutputTime + (i + 1) * outputPeriod - 1;
|
||||
|
||||
for (let j = 0; j < volumesFile.length; j++) {
|
||||
let volume = {
|
||||
buy: volumesFile[j][0],
|
||||
sell: volumesFile[j][1],
|
||||
begin: volumesFile[j][2],
|
||||
end: volumesFile[j][3]
|
||||
}
|
||||
|
||||
/* Here we discard all the Volumes out of range. */
|
||||
if (volume.begin >= outputVolume.begin && volume.end <= outputVolume.end) {
|
||||
|
||||
saveVolume = true;
|
||||
|
||||
outputVolume.buy = outputVolume.buy + volume.buy;
|
||||
outputVolume.sell = outputVolume.sell + volume.sell;
|
||||
}
|
||||
}
|
||||
|
||||
if (saveVolume === true) {
|
||||
outputVolumes[n].push(outputVolume);
|
||||
}
|
||||
}
|
||||
|
||||
writeFiles(outputCandles[n], outputVolumes[n], timeFrame, controlLoop);
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> periodsLoop -> loopBody -> nextVolumeFile -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> buildCandles -> periodsLoop -> controlLoop -> Entering function.")
|
||||
n++
|
||||
if (n < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length) {
|
||||
loopBody()
|
||||
} else {
|
||||
writeStatusReport(contextVariables.lastCandleFile, advanceTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> buildCandles -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeFiles(candles, volumes, timeFrame, callBack) {
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> writeFiles -> Entering function.")
|
||||
/*
|
||||
Here we will write the contents of the Candles and Volumens files.
|
||||
*/
|
||||
try {
|
||||
writeCandles()
|
||||
|
||||
function writeCandles() {
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> writeFiles -> writeCandles -> Entering function.")
|
||||
|
||||
let separator = ""
|
||||
let fileRecordCounter = 0
|
||||
let fileContent = ""
|
||||
|
||||
for (let i = 0; i < candles.length; i++) {
|
||||
let candle = candles[i];
|
||||
fileContent = fileContent + separator + '[' + candles[i].min + "," + candles[i].max + "," + candles[i].open + "," + candles[i].close + "," + candles[i].begin + "," + candles[i].end + "]";
|
||||
if (separator === "") { separator = ","; }
|
||||
fileRecordCounter++
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT +
|
||||
"/Output/" +
|
||||
CANDLES_FOLDER_NAME + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + "/" +
|
||||
timeFrame
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> writeFiles -> writeCandles -> creating file at filePath = " + filePath);
|
||||
|
||||
function onFileCreated(err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> writeFiles -> writeCandles -> onFileCreated -> Entering function.")
|
||||
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeFiles -> writeCandles -> onFileCreated -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> writeFiles -> writeCandles -> onFileCreated -> Finished with File @ " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "_" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName)
|
||||
writeVolumes()
|
||||
}
|
||||
}
|
||||
|
||||
function writeVolumes() {
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
let fileContent = "";
|
||||
|
||||
for (let i = 0; i < volumes.length; i++) {
|
||||
let candle = volumes[i];
|
||||
fileContent = fileContent + separator + '[' + volumes[i].buy + "," + volumes[i].sell + "," + volumes[i].begin + "," + volumes[i].end + "]";
|
||||
if (separator === "") { separator = ","; }
|
||||
fileRecordCounter++
|
||||
}
|
||||
|
||||
fileContent = "[" + fileContent + "]";
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + VOLUMES_FOLDER_NAME + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + "/" + timeFrame;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> writeFiles -> writeVolumes -> creating file at filePath = " + filePath);
|
||||
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeFiles -> writeVolumes -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> writeFiles -> writeVolumes -> onFileCreated -> Finished with File @ " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "_" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName);
|
||||
|
||||
callBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeFiles -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport(lastFileDate, callBack) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate)
|
||||
|
||||
try {
|
||||
let reportKey = "Masters" + "-" + "Candles-Volumes" + "-" + "Multi-Period-Market"
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
thisReport.file.lastExecution = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME
|
||||
thisReport.file.lastFile = lastFileDate
|
||||
thisReport.file.beginingOfMarket = beginingOfMarket.toUTCString()
|
||||
thisReport.save(callBack)
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,27 @@
|
||||
exports.newIndicatorOutput = function newIndicatorOutput(bot, logger, UTILITIES, FILE_STORAGE) {
|
||||
const FULL_LOG = true;
|
||||
exports.newSuperalgosBotModulesIndicatorOutput = function (processIndex) {
|
||||
const MODULE_NAME = "Indicator Bot";
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
start: start
|
||||
};
|
||||
|
||||
let utilities = UTILITIES.newCloudUtilities(logger);
|
||||
let fileStorage = FILE_STORAGE.newFileStorage(logger);
|
||||
|
||||
const COMMONS = require('./Commons.js');
|
||||
let commons = COMMONS.newCommons(bot, logger, UTILITIES, FILE_STORAGE);
|
||||
}
|
||||
|
||||
return thisObject;
|
||||
|
||||
function finalize() {
|
||||
thisObject = undefined
|
||||
utilities = undefined
|
||||
fileStorage = undefined
|
||||
commons = undefined
|
||||
}
|
||||
|
||||
function initialize(callBackFunction) {
|
||||
try {
|
||||
logger.fileName = MODULE_NAME;
|
||||
logger.initialize();
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,15 +40,15 @@
|
||||
}
|
||||
|
||||
/* The first phase here is about checking that we have everything we need at the definition level. */
|
||||
let dataDependencies = global.NODE_BRANCH_TO_ARRAY(bot.processNode.referenceParent.processDependencies, 'Data Dependency')
|
||||
let dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency')
|
||||
|
||||
if (commons.validateDataDependencies(dataDependencies, callBackFunction) !== true) { return }
|
||||
if (TS.projects.superalgos.functionLibraries.singleMarketFunctions.validateDataDependencies(processIndex, dataDependencies, callBackFunction) !== true) { return }
|
||||
|
||||
let outputDatasets = global.NODE_BRANCH_TO_ARRAY (bot.processNode.referenceParent.processOutput, 'Output Dataset')
|
||||
if (commons.validateOutputDatasets(outputDatasets, callBackFunction) !== true) { return }
|
||||
let outputDatasets = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
if (TS.projects.superalgos.functionLibraries.singleMarketFunctions.validateOutputDatasets(processIndex, outputDatasets, callBackFunction) !== true) { return }
|
||||
|
||||
/* The second phase is about transforming the inputs into a format that can be used to apply the user defined code. */
|
||||
commons.inflateDatafiles(dataFiles, dataDependencies, products, mainDependency, timeFrame)
|
||||
TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, timeFrame)
|
||||
|
||||
/* During the third phase, we need to generate the data of the different products this process produces an output */
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
@@ -88,7 +77,7 @@
|
||||
}
|
||||
|
||||
/* Build the data */
|
||||
jsonData = commons.dataBuildingProcedure(
|
||||
jsonData = TS.projects.superalgos.functionLibraries.singleMarketFunctions.dataBuildingProcedure(processIndex,
|
||||
products,
|
||||
mainDependency,
|
||||
recordDefinition,
|
||||
@@ -105,7 +94,7 @@
|
||||
|
||||
/* Add the calculated properties */
|
||||
if (outputDatasetNode.referenceParent.parentNode.calculations !== undefined) {
|
||||
outputData = commons.calculationsProcedure(jsonData, recordDefinition, outputDatasetNode.referenceParent.parentNode.calculations, singularVariableName, timeFrame)
|
||||
outputData = TS.projects.superalgos.functionLibraries.singleMarketFunctions.calculationsProcedure(processIndex, jsonData, recordDefinition, outputDatasetNode.referenceParent.parentNode.calculations, singularVariableName, timeFrame)
|
||||
} else {
|
||||
outputData = jsonData
|
||||
}
|
||||
@@ -130,28 +119,28 @@
|
||||
contextSummary.dataset = outputDatasetNode.referenceParent.config.codeName
|
||||
contextSummary.product = outputDatasetNode.referenceParent.parentNode.config.codeName
|
||||
|
||||
let botNode = global.FIND_NODE_IN_NODE_MESH(outputDatasetNode, 'Indicator Bot')
|
||||
let botNode = TS.projects.superalgos.utilities.nodeFunctions.findNodeInNodeMesh(outputDatasetNode, 'Indicator Bot')
|
||||
contextSummary.bot = botNode.config.codeName
|
||||
let dataMineNode = global.FIND_NODE_IN_NODE_MESH(outputDatasetNode, 'Data Mine')
|
||||
let dataMineNode = TS.projects.superalgos.utilities.nodeFunctions.findNodeInNodeMesh(outputDatasetNode, 'Data Mine')
|
||||
contextSummary.dataMine = dataMineNode.config.codeName
|
||||
contextSummary.mineType = dataMineNode.type.replace(' ', '-')
|
||||
contextSummary.project = dataMineNode.project
|
||||
|
||||
let fileContent = commons.generateFileContent(outputData, outputDatasetNode.referenceParent.parentNode.record, resultsWithIrregularPeriods, processingDailyFiles, currentDay, callBackFunction)
|
||||
commons.writeFile(contextSummary, fileContent, anotherFileWritten, processingDailyFiles, timeFrameLabel, currentDay, callBackFunction)
|
||||
let fileContent = TS.projects.superalgos.functionLibraries.singleMarketFunctions.generateFileContent(processIndex, outputData, outputDatasetNode.referenceParent.parentNode.record, resultsWithIrregularPeriods, processingDailyFiles, currentDay, callBackFunction)
|
||||
TS.projects.superalgos.functionLibraries.singleMarketFunctions.writeFile(processIndex, contextSummary, fileContent, anotherFileWritten, processingDailyFiles, timeFrameLabel, currentDay, callBackFunction)
|
||||
}
|
||||
|
||||
|
||||
function anotherFileWritten() {
|
||||
totalFilesWritten++
|
||||
if (totalFilesWritten === outputDatasets.length) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,625 @@
|
||||
exports.newSuperalgosBotModulesMultiPeriodDaily = function (processIndex) {
|
||||
const MODULE_NAME = "Multi Period Daily"
|
||||
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
start: start
|
||||
};
|
||||
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex)
|
||||
|
||||
let statusDependencies
|
||||
let dataDependenciesModule
|
||||
let dataFiles = new Map
|
||||
let indicatorOutputModule
|
||||
let bootstrappingTheProcess = false
|
||||
let beginingOfMarket
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, pDataDependencies, callBackFunction) {
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
dataDependenciesModule = pDataDependencies;
|
||||
|
||||
indicatorOutputModule = TS.projects.superalgos.botModules.indicatorOutput.newSuperalgosBotModulesIndicatorOutput(processIndex)
|
||||
indicatorOutputModule.initialize(callBackFunction)
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
dataFiles = undefined
|
||||
statusDependencies = undefined
|
||||
dataDependenciesModule = undefined
|
||||
indicatorOutputModule = undefined
|
||||
fileStorage = undefined
|
||||
thisObject = undefined
|
||||
}
|
||||
|
||||
function start(callBackFunction) {
|
||||
try {
|
||||
|
||||
/* Context Variables */
|
||||
let contextVariables = {
|
||||
lastFile: undefined, // Datetime of the last file files sucessfully produced by this process.
|
||||
dateBeginOfMarket: undefined, // Datetime of the first trade file in the whole market history.
|
||||
dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process.
|
||||
};
|
||||
|
||||
let previousDay; // Holds the date of the previous day relative to the processing date.
|
||||
let interExecutionMemoryArray;
|
||||
|
||||
getContextVariables()
|
||||
|
||||
function getContextVariables() {
|
||||
try {
|
||||
let thisReport;
|
||||
let statusReport;
|
||||
/*
|
||||
We look first for the bot who knows the begining of the market in order to get when the market starts.
|
||||
*/
|
||||
statusReport = statusDependencies.reportsByMainUtility.get("Market Starting Point")
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Market Starting Point -> Status Report does not exist or Market Starting Point not defined. Retrying Later. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
thisReport = statusReport.file;
|
||||
|
||||
if (thisReport.beginingOfMarket === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Undefined Last File. -> thisReport.beginingOfMarket === undefined ")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet.")
|
||||
|
||||
let customOK = {
|
||||
result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency does not exist."
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> customOK = " + customOK.message)
|
||||
callBackFunction(customOK)
|
||||
return
|
||||
}
|
||||
|
||||
contextVariables.dateBeginOfMarket = new Date(
|
||||
thisReport.beginingOfMarket.year + "-" +
|
||||
thisReport.beginingOfMarket.month + "-" +
|
||||
thisReport.beginingOfMarket.days + " " +
|
||||
thisReport.beginingOfMarket.hours + ":" +
|
||||
thisReport.beginingOfMarket.minutes +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS
|
||||
)
|
||||
/*
|
||||
Here we get the status report from the bot who knows which is the end of the market.
|
||||
*/
|
||||
statusReport = statusDependencies.reportsByMainUtility.get("Market Ending Point")
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Market Ending Point -> Status Report does not exist or Market Ending Point not defined. Retrying Later. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
thisReport = statusReport.file;
|
||||
|
||||
if (thisReport.lastFile === undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Undefined Last File. -> thisReport.lastFile === undefined")
|
||||
|
||||
let customOK = {
|
||||
result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result,
|
||||
message: "Dependency not ready."
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> customOK = " + customOK.message)
|
||||
callBackFunction(customOK)
|
||||
return
|
||||
}
|
||||
|
||||
contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf())
|
||||
|
||||
/* Finally we get our own Status Report. */
|
||||
statusReport = statusDependencies.reportsByMainUtility.get("Self Reference")
|
||||
|
||||
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> getContextVariables -> Self Reference -> Status Report does not exist or Self Reference not defined or badly configured. Check that at the Status Dependency you have chosen Self Reference at the config. Retrying Later. ")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
if (statusReport.status === "Status Report is corrupt.") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
thisReport = statusReport.file;
|
||||
|
||||
if (thisReport.lastFile !== undefined) {
|
||||
|
||||
beginingOfMarket = new Date(thisReport.beginingOfMarket)
|
||||
|
||||
if (beginingOfMarket.valueOf() !== contextVariables.dateBeginOfMarket.valueOf()) { // Reset Mechanism for Begining of the Market
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Reset Mechanism for Begining of the Market Activated.")
|
||||
|
||||
beginingOfMarket = new Date(contextVariables.dateBeginOfMarket.valueOf())
|
||||
startFromBegining()
|
||||
return
|
||||
}
|
||||
|
||||
contextVariables.lastFile = new Date(thisReport.lastFile)
|
||||
interExecutionMemoryArray = thisReport.interExecutionMemoryArray;
|
||||
|
||||
processTimeFrames()
|
||||
} else {
|
||||
|
||||
/*
|
||||
In the case when there is no status report, we assume like the last processed file is the one on the date of Begining of Market.
|
||||
*/
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> Starting from the begining of the market because own status report not found or lastFile was undefined.")
|
||||
beginingOfMarket = new Date(contextVariables.dateBeginOfMarket.valueOf())
|
||||
startFromBegining()
|
||||
}
|
||||
|
||||
function startFromBegining() {
|
||||
contextVariables.lastFile = new Date(
|
||||
contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" +
|
||||
(contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" +
|
||||
contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" +
|
||||
TS.projects.superalgos.globals.timeConstants.GMT_SECONDS
|
||||
)
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> startFromBegining -> contextVariables.lastFile = " + contextVariables.lastFile)
|
||||
/*
|
||||
The first time the process is running is the right time to create the data structure that is going to be shared across different executions.
|
||||
This data structure has one object per each timeFrame.
|
||||
*/
|
||||
interExecutionMemoryArray = []
|
||||
/*
|
||||
Also, we will remember that we are bootstrapping the process, this will allow us, to advanceTime if necesary.
|
||||
It can happen that a process depends on data from another process that does not produce a file during the first day, or even more days,
|
||||
in that situation we want the process not to just wait for that data that will never arrive, but to advance time until it finds valid data.
|
||||
*/
|
||||
bootstrappingTheProcess = true
|
||||
|
||||
for (let i = 0; i < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; i++) {
|
||||
let emptyObject = {};
|
||||
interExecutionMemoryArray.push(emptyObject)
|
||||
}
|
||||
|
||||
processTimeFrames()
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> err = " + err.stack)
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys))
|
||||
}
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function processTimeFrames() {
|
||||
let n;
|
||||
let botNeverRan = true;
|
||||
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME =
|
||||
new Date(contextVariables.lastFile.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) // Go back one day to start well when we advance time at the begining of the loop.
|
||||
let fromDate = new Date(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.valueOf())
|
||||
let lastDate = new Date()
|
||||
|
||||
advanceTime()
|
||||
|
||||
function advanceTime() {
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME =
|
||||
new Date(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.valueOf() +
|
||||
TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
previousDay = new Date(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.valueOf() -
|
||||
TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> processTimeFrames -> advanceTime -> TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME = " +
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> processTimeFrames -> advanceTime -> previousDay = " + previousDay)
|
||||
|
||||
/* Validation that we are not going past the head of the market. */
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.valueOf() > contextVariables.dateEndOfMarket.valueOf()) {
|
||||
|
||||
const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + ".";
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> processTimeFrames -> advanceTime -> " + logText)
|
||||
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.getUTCFullYear() + '-' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.getUTCMonth() + 1, 2) + '-' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.getUTCDate(), 2)
|
||||
let currentDate = new Date(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME)
|
||||
let percentage = TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(fromDate, currentDate, lastDate)
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, currentDateString, percentage)
|
||||
|
||||
if (TS.projects.superalgos.utilities.dateTimeFunctions.areTheseDatesEqual(currentDate, new Date()) === false) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newInternalLoop(currentDate, percentage)
|
||||
}
|
||||
checkStopTaskGracefully()
|
||||
}
|
||||
function checkStopTaskGracefully() {
|
||||
/* Validation that we dont need to stop. */
|
||||
if (TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING === true) {
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
}
|
||||
timeFramesLoop()
|
||||
}
|
||||
|
||||
function timeFramesLoop() {
|
||||
/*
|
||||
We will iterate through all posible timeFrames.
|
||||
*/
|
||||
n = 0 // loop Variable representing each possible period as defined at the timeFrames array.
|
||||
timeFramesLoopBody()
|
||||
}
|
||||
|
||||
function timeFramesLoopBody() {
|
||||
|
||||
const timeFrame = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][0]
|
||||
const timeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]
|
||||
|
||||
/* Check Time Frames Filter */
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.dailyTimeFrames !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.dailyTimeFrames.includes(timeFrameLabel) === false) {
|
||||
/* We are not going to process this Time Frame */
|
||||
timeFramesControlLoop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validPeriods !== undefined) {
|
||||
let validPeriod = false;
|
||||
for (let i = 0; i < TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validPeriods.length; i++) {
|
||||
let period = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validPeriods[i]
|
||||
if (period === timeFrameLabel) { validPeriod = true }
|
||||
}
|
||||
if (validPeriod === false) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> processTimeFrames -> timeFramesLoopBody -> Discarding period for not being listed as a valid period. -> timeFrameLabel = " + timeFrameLabel)
|
||||
timeFramesControlLoop()
|
||||
return
|
||||
}
|
||||
}
|
||||
let dependencyIndex = 0
|
||||
dataFiles = new Map()
|
||||
|
||||
dependencyLoopBody()
|
||||
|
||||
function dependencyLoopBody() {
|
||||
let dependency = dataDependenciesModule.nodeArray[dependencyIndex]
|
||||
if (dependency === undefined) {
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> processTimeFrames -> timeFramesLoopBody -> dependencyLoopBody -> You need to add at least one Data Dependency to the process Multi Period Daily. Aborting process.")
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]
|
||||
let previousFile
|
||||
let currentFile
|
||||
|
||||
if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.valueOf() > contextVariables.dateBeginOfMarket.valueOf()) {
|
||||
getPreviousFile()
|
||||
} else {
|
||||
previousFile = []
|
||||
getCurrentFile()
|
||||
}
|
||||
|
||||
function getPreviousFile() {
|
||||
let dateForPath = previousDay.getUTCFullYear() + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(previousDay.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(previousDay.getUTCDate(), 2)
|
||||
let filePath
|
||||
if (dependency.referenceParent.config.codeName === "Multi-Period-Daily") {
|
||||
filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath;
|
||||
} else {
|
||||
filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + dateForPath;
|
||||
}
|
||||
let fileName = "Data.json"
|
||||
|
||||
datasetModule.getTextFile(filePath, fileName, onFileReceived)
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
if ((err.message === "File does not exist." && botNeverRan === true) || err.code === 'The specified key does not exist.') {
|
||||
/*
|
||||
Sometimes one of the dependencies of an indicator for some reasons are not calculated from the begining of the market.
|
||||
When that happens we can not find those files. What we do in this situation is to move the time fordward until we can find
|
||||
all the dependencies and the first run of the bot is successful.
|
||||
|
||||
After that, we will not accept more missing files on any of the dependencies, and if any is missing we will abort the processing.
|
||||
*/
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] start -> processTimeFrames -> timeFramesLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> Skipping day because file " + filePath + "/" + fileName + " was not found.")
|
||||
|
||||
advanceTime()
|
||||
return
|
||||
}
|
||||
|
||||
if ((err.result === "Fail Because" && err.message === "File does not exist.") || err.code === 'The specified key does not exist.') {
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> processTimeFrames -> timeFramesLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.stack)
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> processTimeFrames -> timeFramesLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
previousFile = JSON.parse(text)
|
||||
getCurrentFile()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getCurrentFile() {
|
||||
let dateForPath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.getUTCFullYear() + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME.getUTCDate(), 2)
|
||||
let filePath
|
||||
if (dependency.referenceParent.config.codeName === "Multi-Period-Daily") {
|
||||
filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath;
|
||||
} else {
|
||||
filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + dateForPath;
|
||||
}
|
||||
let fileName = "Data.json";
|
||||
|
||||
datasetModule.getTextFile(filePath, fileName, onFileReceived)
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
if ((err.result === "Fail Because" && err.message === "File does not exist.") || err.code === 'The specified key does not exist.') {
|
||||
if (bootstrappingTheProcess === true) {
|
||||
/*
|
||||
In the special situation where we are running this process for the first time (no status report found),
|
||||
we will consider the possibility that a depanant process does not produce a file during the first day of the market,
|
||||
or even more than one day. That is why we are going to advance time here.
|
||||
*/
|
||||
advanceTime()
|
||||
return
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> processTimeFrames -> timeFramesLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.code)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> processTimeFrames -> timeFramesLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> processTimeFrames -> timeFramesLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName)
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> processTimeFrames -> timeFramesLoopBody -> dependencyLoopBody -> getCurrentFile -> Not OK -> onFileReceived -> err = " + err.code)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
currentFile = JSON.parse(text)
|
||||
let dataFile = previousFile.concat(currentFile)
|
||||
dataFiles.set(dependency.id, dataFile)
|
||||
dependencyControlLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function dependencyControlLoop() {
|
||||
dependencyIndex++;
|
||||
if (dependencyIndex < dataDependenciesModule.nodeArray.length) {
|
||||
dependencyLoopBody()
|
||||
} else {
|
||||
generateOutput()
|
||||
}
|
||||
|
||||
function generateOutput() {
|
||||
|
||||
indicatorOutputModule.start(
|
||||
dataFiles,
|
||||
timeFrame,
|
||||
timeFrameLabel,
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME,
|
||||
interExecutionMemoryArray[n],
|
||||
onOutputGenerated)
|
||||
|
||||
function onOutputGenerated(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
botNeverRan = false;
|
||||
timeFramesControlLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function timeFramesControlLoop() {
|
||||
n++
|
||||
if (n < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length) {
|
||||
timeFramesLoopBody()
|
||||
} else {
|
||||
n = 0;
|
||||
writeDataRanges(onWritten)
|
||||
|
||||
function onWritten(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> processTimeFrames -> controlLoop -> onWritten -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
writeStatusReport(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME, advanceTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeDataRanges(callBack) {
|
||||
let outputDatasets = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
let outputDatasetIndex = -1;
|
||||
controlLoop()
|
||||
|
||||
function productLoopBody() {
|
||||
let productCodeName = outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName;
|
||||
writeDataRange(
|
||||
contextVariables.dateBeginOfMarket,
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).DAILY_FILES_PROCESS_DATETIME,
|
||||
productCodeName,
|
||||
controlLoop
|
||||
)
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
outputDatasetIndex++
|
||||
if (outputDatasetIndex < outputDatasets.length) {
|
||||
productLoopBody()
|
||||
} else {
|
||||
callBack(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeDataRange(pBegin, pEnd, productCodeName, callBack) {
|
||||
let dataRange = {
|
||||
begin: pBegin.valueOf(),
|
||||
end: pEnd.valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS
|
||||
};
|
||||
let fileContent = JSON.stringify(dataRange)
|
||||
let fileName = '/Data.Range.json';
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + productCodeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + fileName;
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated)
|
||||
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
}
|
||||
let key = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + productCodeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
let event = {
|
||||
dateRange: dataRange
|
||||
}
|
||||
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.raiseEvent(key, 'Data Range Updated', event)
|
||||
writeTimeFramesFile(productCodeName, callBack)
|
||||
}
|
||||
}
|
||||
|
||||
function writeTimeFramesFile(productCodeName, callBack) {
|
||||
|
||||
let timeFramesArray = []
|
||||
for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; n++) {
|
||||
let timeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]
|
||||
|
||||
/* Check Time Frames Filter */
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.dailyTimeFrames !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.dailyTimeFrames.includes(timeFrameLabel) === true) {
|
||||
timeFramesArray.push(timeFrameLabel)
|
||||
}
|
||||
} else {
|
||||
timeFramesArray.push(timeFrameLabel)
|
||||
}
|
||||
} else {
|
||||
timeFramesArray.push(timeFrameLabel)
|
||||
}
|
||||
}
|
||||
|
||||
let fileContent = JSON.stringify(timeFramesArray)
|
||||
let fileName = '/Time.Frames.json';
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + productCodeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + fileName;
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated)
|
||||
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeTimeFramesFiles -> onFileCreated -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
}
|
||||
callBack(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport(lastFileDate, callBack) {
|
||||
let reportKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + "Multi-Period-Daily"
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
thisReport.file.lastFile = lastFileDate;
|
||||
thisReport.file.interExecutionMemoryArray = interExecutionMemoryArray;
|
||||
thisReport.file.beginingOfMarket = beginingOfMarket.toUTCString()
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.dailyTimeFrames !== undefined) {
|
||||
thisReport.file.timeFrames = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.dailyTimeFrames
|
||||
}
|
||||
}
|
||||
thisReport.save(callBack)
|
||||
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> err = " + err.stack)
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,227 @@
|
||||
exports.newSuperalgosBotModulesMultiPeriodMarket = function (processIndex) {
|
||||
const MODULE_NAME = "Multi Period Market";
|
||||
thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
start: start
|
||||
};
|
||||
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex)
|
||||
|
||||
let statusDependencies
|
||||
let dataDependenciesModule
|
||||
let dataFiles = new Map()
|
||||
let indicatorOutputModule
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, pDataDependencies, callBackFunction) {
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
dataDependenciesModule = pDataDependencies;
|
||||
|
||||
indicatorOutputModule = TS.projects.superalgos.botModules.indicatorOutput.newSuperalgosBotModulesIndicatorOutput(processIndex)
|
||||
indicatorOutputModule.initialize(callBackFunction)
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
fileStorage = undefined
|
||||
dataFiles = undefined
|
||||
statusDependencies = undefined
|
||||
dataDependenciesModule = undefined
|
||||
indicatorOutputModule = undefined
|
||||
thisObject = undefined
|
||||
}
|
||||
|
||||
function start(callBackFunction) {
|
||||
try {
|
||||
processTimeFrames()
|
||||
|
||||
function processTimeFrames() {
|
||||
let n;
|
||||
timeFramesLoop()
|
||||
|
||||
function timeFramesLoop() {
|
||||
/* We will iterate through all posible timeFrames.*/
|
||||
n = 0 // loop Variable representing each possible period as defined at the timeFrames array.
|
||||
timeFramesLoopBody()
|
||||
}
|
||||
|
||||
function timeFramesLoopBody() {
|
||||
const timeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0]
|
||||
const timeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]
|
||||
|
||||
/* Check Time Frames Filter */
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.marketTimeFrames !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.marketTimeFrames.includes(timeFrameLabel) === false) {
|
||||
/* We are not going to process this Time Frame */
|
||||
timeFramesControlLoop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let dependencyIndex = 0;
|
||||
dataFiles = new Map;
|
||||
|
||||
dependencyLoopBody()
|
||||
|
||||
function dependencyLoopBody() {
|
||||
let dependency = dataDependenciesModule.nodeArray[dependencyIndex]
|
||||
let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]
|
||||
|
||||
getFile()
|
||||
|
||||
function getFile() {
|
||||
let fileName = "Data.json";
|
||||
let filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel;
|
||||
datasetModule.getTextFile(filePath, fileName, onFileReceived)
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> processTimeFrames -> timeFramesLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.stack)
|
||||
callBackFunction(err)
|
||||
return;
|
||||
}
|
||||
|
||||
let dataFile = JSON.parse(text)
|
||||
dataFiles.set(dependency.id, dataFile)
|
||||
|
||||
dependencyControlLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function dependencyControlLoop() {
|
||||
dependencyIndex++;
|
||||
if (dependencyIndex < dataDependenciesModule.nodeArray.length) {
|
||||
dependencyLoopBody()
|
||||
} else {
|
||||
generateOutput()
|
||||
}
|
||||
|
||||
function generateOutput() {
|
||||
indicatorOutputModule.start(
|
||||
dataFiles,
|
||||
timeFrame,
|
||||
timeFrameLabel,
|
||||
undefined,
|
||||
undefined,
|
||||
onOutputGenerated)
|
||||
|
||||
function onOutputGenerated(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
callBackFunction(err)
|
||||
return;
|
||||
}
|
||||
timeFramesControlLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function timeFramesControlLoop() {
|
||||
n++;
|
||||
if (n < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length) {
|
||||
timeFramesLoopBody()
|
||||
} else {
|
||||
writeTimeFramesFiles(onTimeFrameFilesWritten)
|
||||
function onTimeFrameFilesWritten() {
|
||||
writeStatusReport(callBackFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeTimeFramesFiles(callBack) {
|
||||
let outputDatasets =
|
||||
TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset')
|
||||
let outputDatasetIndex = -1;
|
||||
controlLoop()
|
||||
|
||||
function productLoopBody() {
|
||||
let productCodeName = outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName;
|
||||
writeTimeFramesFile(productCodeName, controlLoop)
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
outputDatasetIndex++
|
||||
if (outputDatasetIndex < outputDatasets.length) {
|
||||
productLoopBody()
|
||||
} else {
|
||||
callBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeTimeFramesFile(productCodeName, callBack) {
|
||||
|
||||
let timeFramesArray = []
|
||||
for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; n++) {
|
||||
let timeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]
|
||||
|
||||
/* Check Time Frames Filter */
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.marketTimeFrames !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.marketTimeFrames.includes(timeFrameLabel) === true) {
|
||||
timeFramesArray.push(timeFrameLabel)
|
||||
}
|
||||
} else {
|
||||
timeFramesArray.push(timeFrameLabel)
|
||||
}
|
||||
} else {
|
||||
timeFramesArray.push(timeFrameLabel)
|
||||
}
|
||||
}
|
||||
|
||||
let fileContent = JSON.stringify(timeFramesArray)
|
||||
let fileName = '/Time.Frames.json';
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + productCodeName + "/" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + fileName;
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated)
|
||||
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeTimeFramesFile -> onFileCreated -> err = " + err.stack)
|
||||
callBack(err)
|
||||
return
|
||||
}
|
||||
callBack()
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport(callBack) {
|
||||
let reportKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + "Multi-Period-Market"
|
||||
let thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
thisReport.file.lastExecution = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME;
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.marketTimeFrames !== undefined) {
|
||||
thisReport.file.timeFrames = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.timeFramesFilter.config.marketTimeFrames
|
||||
}
|
||||
}
|
||||
thisReport.save(callBack)
|
||||
|
||||
if (TS.projects.superalgos.utilities.dateTimeFunctions.areTheseDatesEqual(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME, new Date()) === false) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newInternalLoop(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME)
|
||||
}
|
||||
|
||||
/* Telling the world we are alive and doing well */
|
||||
let currentDateString = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME.getUTCDate(), 2)
|
||||
let currentDate = new Date(TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME)
|
||||
let lastDate = new Date()
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, currentDateString, TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(currentDate, currentDate, lastDate))
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> err = " + err.stack)
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,823 @@
|
||||
exports.newSuperalgosBotModulesSingleMarketIndicatorBot = function (processIndex) {
|
||||
|
||||
const MODULE_NAME = "Single Market Indicator Bot";
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
run: run
|
||||
}
|
||||
|
||||
let nextLoopTimeoutHandle
|
||||
let botModuleObject
|
||||
|
||||
return thisObject
|
||||
|
||||
function initialize(callBackFunction) {
|
||||
try {
|
||||
/* We will check that we have received all the nodes needed to run this bot. */
|
||||
if (TS.projects.superalgos.functionLibraries.singleMarketFunctions.checkUpstreamOfTaskNode(processIndex) === false) {
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
/* Here we setup the path prefix that will be used when writting data or logs to disk. */
|
||||
TS.projects.superalgos.functionLibraries.singleMarketFunctions.initializeFilePathRoot(processIndex)
|
||||
|
||||
/*
|
||||
Bots can be defined at the UI, using one of the available existing frameworks for that,
|
||||
or they might be coded at a bot module. In the later case, the name of the botModule
|
||||
must be specified at the bot process config.
|
||||
*/
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.botModule === undefined) {
|
||||
/* The code of the bot is defined at the UI. No need to load a file with the code. */
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
return
|
||||
} else {
|
||||
/*
|
||||
Here we will need to scan the PROJECTS SCHEMA in order to find the botModule
|
||||
defined for this Sensor Bot.
|
||||
*/
|
||||
let botModuleDefinition = TS.projects.superalgos.functionLibraries.taskFunctions.getBotModuleByName(
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.botModule
|
||||
)
|
||||
let project = TS.projects[TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName.toLowerCase()]
|
||||
let botModule = project.botModules[botModuleDefinition.propertyName]
|
||||
let moduleFunction = botModule[botModuleDefinition.functionName]
|
||||
botModuleObject = moduleFunction(processIndex)
|
||||
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] initialize -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function run(callBackFunction) {
|
||||
try {
|
||||
loop();
|
||||
|
||||
function loop() {
|
||||
try {
|
||||
function pad(str, max) {
|
||||
str = str.toString();
|
||||
return str.length < max ? pad(" " + str, max) : str;
|
||||
}
|
||||
|
||||
/* For each loop we want to create a new log file. */
|
||||
if (TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT !== undefined) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.finalize()
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT =
|
||||
TS.projects.superalgos.taskModules.debugLog.newSuperalgosTaskModulesDebugLog(processIndex)
|
||||
TS.projects.superalgos.globals.taskVariables.LOGGER_MAP.set(
|
||||
MODULE_NAME + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].id,
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT
|
||||
)
|
||||
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).MAIN_LOOP_COUNTER++;
|
||||
|
||||
/* We tell the UI that we are running. */
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex)
|
||||
|
||||
/* We define the datetime for the process that we are running now. This will be the official processing time for both the infraestructure and the bot. */
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME = new Date(); // This will be considered the process date and time, so as to have it consistenly all over the execution.
|
||||
|
||||
/* Main Loop Console Logging */
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newMainLoop()
|
||||
|
||||
/* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */
|
||||
let processExecutionEvents
|
||||
let processFramework;
|
||||
let statusDependencies;
|
||||
let dataDependencies;
|
||||
|
||||
let nextWaitTime;
|
||||
|
||||
initializeProcessExecutionEvents();
|
||||
|
||||
function initializeProcessExecutionEvents() {
|
||||
try {
|
||||
processExecutionEvents = TS.projects.superalgos.processModules.processExecutionEvents.newSuperalgosProcessModulesProcessExecutionEvents(processIndex)
|
||||
processExecutionEvents.initialize(onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Execution finished well.");
|
||||
startProcessExecutionEvents()
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeProcessExecutionEvents -> onInizialized -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeProcessExecutionEvents -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function startProcessExecutionEvents() {
|
||||
try {
|
||||
processExecutionEvents.start(onStarted);
|
||||
|
||||
function onStarted(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> startProcessExecutionEvents -> onStarted -> Execution finished well.");
|
||||
|
||||
if (TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING === true) {
|
||||
loopControl()
|
||||
return
|
||||
}
|
||||
|
||||
initializeStatusDependencies();
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startProcessExecutionEvents -> onStarted -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessExecutionEvents -> onStarted -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessExecutionEvents -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function initializeStatusDependencies() {
|
||||
try {
|
||||
statusDependencies = TS.projects.superalgos.processModules.statusDependencies.newSuperalgosProcessModulesStatusDependencies(processIndex);
|
||||
statusDependencies.initialize(onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> initializeStatusDependencies -> onInizialized -> Execution finished well.");
|
||||
initializeDataDependencies();
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> initializeStatusDependencies -> onInizialized -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeStatusDependencies -> onInizialized -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeStatusDependencies -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function initializeDataDependencies() {
|
||||
try {
|
||||
dataDependencies = TS.projects.superalgos.processModules.dataDependencies.newSuperalgosProcessModulesDataDependencies(processIndex);
|
||||
dataDependencies.initialize(onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
/* If the process is configured to run inside a framework, we continue there, otherwise we run the bot directly. */
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework === undefined) {
|
||||
initializeBotModuleObject();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.name) {
|
||||
case 'Multi-Period-Market': {
|
||||
processFramework = TS.projects.superalgos.botModules.multiPeriodMarket.newSuperalgosBotModulesMultiPeriodMarket(processIndex);
|
||||
intitializeProcessFramework();
|
||||
break;
|
||||
}
|
||||
case 'Multi-Period-Daily': {
|
||||
processFramework = TS.projects.superalgos.botModules.multiPeriodDaily.newSuperalgosBotModulesMultiPeriodDaily(processIndex);
|
||||
intitializeProcessFramework();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework not Supported.");
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework Name = " +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.name);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> initializeDataDependencies -> onInizialized -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
processStopped()
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeDataDependencies -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function initializeBotModuleObject() {
|
||||
try {
|
||||
botModuleObject.initialize(statusDependencies, onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> initializeBotModuleObject -> onInizialized -> Execution finished well.");
|
||||
startBotModuleObject();
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> initializeBotModuleObject -> onInizialized -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeBotModuleObject -> onInizialized -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result: {
|
||||
|
||||
switch (err.message) {
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeBotModuleObject -> onInizialized > Unhandled custom response received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeBotModuleObject -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeBotModuleObject -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeBotModuleObject -> onInizialized -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> initializeBotModuleObject -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function startBotModuleObject() {
|
||||
try {
|
||||
botModuleObject.start(onFinished);
|
||||
|
||||
function onFinished(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> startBotModuleObject -> onFinished -> Execution finished well.");
|
||||
finishProcessExecutionEvents()
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startBotModuleObject -> onFinished -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startBotModuleObject -> onFinished -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result: {
|
||||
|
||||
switch (err.message) {
|
||||
case "Dependency does not exist.": {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startBotModuleObject -> onFinished -> Dependency does not exist. This Loop will go to sleep.");
|
||||
nextWaitTime = 'Sleep';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case "Dependency not ready.": {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startBotModuleObject -> onFinished -> Dependency not ready. Will Retry Later.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startBotModuleObject -> onFinished -> Unhandled custom response received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startBotModuleObject -> onFinished -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startBotModuleObject -> onFinished -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startBotModuleObject -> onFinished -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startBotModuleObject -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function intitializeProcessFramework() {
|
||||
try {
|
||||
processFramework.initialize(statusDependencies, dataDependencies, onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
try {
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> intitializeProcessFramework -> onInizialized -> Execution finished well.");
|
||||
startProcessFramework();
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> intitializeProcessFramework -> onInizialized -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result: {
|
||||
|
||||
switch (err.message) {
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized > Unhandled custom response received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> intitializeProcessFramework -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function startProcessFramework() {
|
||||
try {
|
||||
processFramework.start(onFinished);
|
||||
|
||||
function onFinished(err) {
|
||||
try {
|
||||
processFramework.finalize()
|
||||
processFramework = undefined
|
||||
dataDependencies.finalize()
|
||||
dataDependencies = undefined
|
||||
statusDependencies.finalize()
|
||||
statusDependencies = undefined
|
||||
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> startProcessFramework -> onFinished -> Execution finished well.");
|
||||
finishProcessExecutionEvents()
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startProcessFramework -> onFinished -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> onFinished -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result: {
|
||||
|
||||
switch (err.message) {
|
||||
case "Dependency does not exist.": {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency does not exist. This Loop will go to sleep.");
|
||||
nextWaitTime = 'Sleep';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case "Dependency not ready.": {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency not ready. This Loop will go to sleep.");
|
||||
nextWaitTime = 'Sleep';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled custom response received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> onFinished -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> startProcessFramework -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function finishProcessExecutionEvents() {
|
||||
try {
|
||||
processExecutionEvents.finish(onFinished);
|
||||
|
||||
function onFinished(err) {
|
||||
try {
|
||||
processExecutionEvents.finalize()
|
||||
processExecutionEvents = undefined
|
||||
|
||||
switch (err.result) {
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> finishProcessExecutionEvents -> onFinished -> Execution finished well.");
|
||||
nextWaitTime = 'Normal';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[WARN] run -> loop -> finishProcessExecutionEvents -> onFinished -> Retry Later. Requesting Execution Retry.");
|
||||
nextWaitTime = 'Retry';
|
||||
loopControl(nextWaitTime);
|
||||
return;
|
||||
}
|
||||
case TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Operation Failed. Aborting the process.");
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
default: {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Unhandled err.result received. -> err.result = " + err.result);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> Unhandled err.result received. -> err = " + err.message);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> finishProcessExecutionEvents -> onFinished -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> finishProcessExecutionEvents -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function loopControl(nextWaitTime) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> nextWaitTime = " + nextWaitTime)
|
||||
|
||||
/* We show we reached the end of the loop. */
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex)
|
||||
|
||||
/* Here we check if we must stop the loop gracefully. */
|
||||
shallWeStop(onStop, onContinue);
|
||||
|
||||
function onStop() {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> onStop -> Stopping the Loop Gracefully. See you next time!")
|
||||
processStopped()
|
||||
return;
|
||||
}
|
||||
|
||||
function onContinue() {
|
||||
/* Indicator bots are going to be executed after a configured period of time after the last execution ended. This is to avoid overlapping executions. */
|
||||
switch (nextWaitTime) {
|
||||
case 'Normal': {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> Restarting Loop in " +
|
||||
(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.normalWaitTime / 1000) + " seconds.")
|
||||
nextLoopTimeoutHandle = setTimeout(loop, TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.normalWaitTime);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Waiting " +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.normalWaitTime / 1000 + " seconds for next execution.")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
}
|
||||
break;
|
||||
case 'Retry': {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> Restarting Loop in " +
|
||||
(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.retryWaitTime / 1000) + " seconds.")
|
||||
nextLoopTimeoutHandle = setTimeout(loop, TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.retryWaitTime);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Trying to recover from some problem. Waiting " +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.retryWaitTime / 1000 + " seconds for next execution.")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
}
|
||||
break;
|
||||
case 'Sleep': {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> Restarting Loop in " +
|
||||
(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.sleepWaitTime / 60000) + " minutes.")
|
||||
nextLoopTimeoutHandle = setTimeout(loop, TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.sleepWaitTime);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Waiting " +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.sleepWaitTime / 60000 + " minutes for next execution.")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
}
|
||||
break;
|
||||
case 'Coma': {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] run -> loop -> loopControl -> Restarting Loop in " +
|
||||
(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.comaWaitTime / 3600000) + " hours.")
|
||||
nextLoopTimeoutHandle = setTimeout(loop, TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.comaWaitTime);
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, undefined, undefined, "Waiting " +
|
||||
TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.comaWaitTime / 3600000 + " hours for next execution.")
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shallWeStop(stopCallBack, continueCallBack) {
|
||||
try {
|
||||
/* IMPORTANT: This function is exactly the same on the 3 modules. */
|
||||
if (!TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING) {
|
||||
continueCallBack();
|
||||
} else {
|
||||
stopCallBack();
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> shallWeStop -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> loop -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE = err.message
|
||||
processStopped()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function processStopped() {
|
||||
if (TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE !== undefined) {
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processError(
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_KEY, undefined, "An unexpected error caused the Process to stop.")
|
||||
} else {
|
||||
TS.projects.superalgos.globals.taskConstants.EVENT_SERVER_CLIENT_MODULE_OBJECT.raiseEvent(
|
||||
TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_KEY, 'Stopped')
|
||||
}
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.persist();
|
||||
clearTimeout(nextLoopTimeoutHandle);
|
||||
if (TS.projects.superalgos.globals.taskVariables.FATAL_ERROR_MESSAGE !== undefined) {
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
||||
} else {
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_INSTANCE_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] run -> err = " + err.stack);
|
||||
clearTimeout(nextLoopTimeoutHandle);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,9 +1,7 @@
|
||||
|
||||
exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_STORAGE, STATUS_REPORT, EXCHANGE_API) {
|
||||
exports.newSuperalgosBotModulesHistoricOHLCVs = function (processIndex) {
|
||||
|
||||
const FULL_LOG = true;
|
||||
const GMT_SECONDS = ':00.000 GMT+0000';
|
||||
const MODULE_NAME = "User Bot";
|
||||
const MODULE_NAME = "Historic OHLCVs";
|
||||
const CANDLES_FOLDER_NAME = "Candles/One-Min";
|
||||
const VOLUMES_FOLDER_NAME = "Volumes/One-Min";
|
||||
|
||||
@@ -12,15 +10,11 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
start: start
|
||||
};
|
||||
|
||||
let utilities = UTILITIES.newCloudUtilities(bot, logger)
|
||||
let fileStorage = FILE_STORAGE.newFileStorage(logger);
|
||||
let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex);
|
||||
let statusDependencies
|
||||
|
||||
const ONE_MIN = 60000
|
||||
const ONE_DAY = ONE_MIN * 60 * 24
|
||||
|
||||
const MAX_OHLCVs_PER_EXECUTION = 10000000
|
||||
const symbol = bot.market.baseAsset + '/' + bot.market.quotedAsset
|
||||
const symbol = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
||||
const ccxt = require('ccxt')
|
||||
|
||||
let fetchType = "by Time"
|
||||
@@ -36,7 +30,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
let options = {}
|
||||
let rateLimit = 500
|
||||
let exchange
|
||||
let uiStartDate = new Date(bot.uiStartDate)
|
||||
let uiStartDate = new Date(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.config.startDate)
|
||||
let fisrtTimeThisProcessRun = false
|
||||
let limit = 1000 // This is the default value
|
||||
let hostname
|
||||
@@ -48,52 +42,44 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
let exchangeClass
|
||||
|
||||
try {
|
||||
|
||||
logger.fileName = MODULE_NAME;
|
||||
logger.initialize();
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
|
||||
exchangeId = bot.exchange.toLowerCase().replace(' ', '')
|
||||
exchangeId = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name.toLowerCase().replace(' ', '')
|
||||
|
||||
/* Applying the parameters defined by the user at the Exchange Node Config */
|
||||
if (bot.exchangeNode.config.API !== undefined) {
|
||||
for (let i = 0; i < bot.exchangeNode.config.API.length; i++) {
|
||||
if (bot.exchangeNode.config.API[i].method === 'fetch_ohlcv') {
|
||||
if (bot.exchangeNode.config.API[i].class !== undefined) {
|
||||
exchangeId = bot.exchangeNode.config.API[i].class
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API !== undefined) {
|
||||
for (let i = 0; i < TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API.length; i++) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].method === 'fetch_ohlcv') {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].class !== undefined) {
|
||||
exchangeId = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].class
|
||||
}
|
||||
if (bot.exchangeNode.config.API[i].fetchOHLCVsMethod !== undefined) {
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].fetchOHLCVsMethod !== undefined) {
|
||||
options = {
|
||||
'fetchOHLCVsMethod': bot.exchangeNode.config.API[i].fetchOHLCVsMethod
|
||||
'fetchOHLCVsMethod': TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].fetchOHLCVsMethod
|
||||
}
|
||||
}
|
||||
if (bot.exchangeNode.config.API[i].firstId !== undefined) {
|
||||
firstId = bot.exchangeNode.config.API[i].firstId
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].firstId !== undefined) {
|
||||
firstId = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].firstId
|
||||
}
|
||||
if (bot.exchangeNode.config.API[i].rateLimit !== undefined) {
|
||||
rateLimit = bot.exchangeNode.config.API[i].rateLimit
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].rateLimit !== undefined) {
|
||||
rateLimit = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].rateLimit
|
||||
}
|
||||
if (bot.exchangeNode.config.API[i].hostname !== undefined) {
|
||||
hostname = bot.exchangeNode.config.API[i].hostname
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].hostname !== undefined) {
|
||||
hostname = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].hostname
|
||||
}
|
||||
if (bot.exchangeNode.config.API[i].fetchType !== undefined) {
|
||||
fetchType = bot.exchangeNode.config.API[i].fetchType
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].fetchType !== undefined) {
|
||||
fetchType = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API[i].fetchType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bot.config.fetchLimit !== undefined) {
|
||||
limit = bot.config.fetchLimit
|
||||
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.config.fetchLimit !== undefined) {
|
||||
limit = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.config.fetchLimit
|
||||
}
|
||||
|
||||
let key = process.env.KEY
|
||||
let secret = process.env.SECRET
|
||||
|
||||
if (key === "undefined") { key = undefined }
|
||||
if (secret === "undefined") { secret = undefined }
|
||||
|
||||
let key
|
||||
let secret
|
||||
|
||||
exchangeClass = ccxt[exchangeId]
|
||||
const exchangeConstructorParams = {
|
||||
@@ -113,10 +99,10 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
|
||||
exchange = new exchangeClass(exchangeConstructorParams)
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
|
||||
|
||||
/* CCXT Supported Exchanges */
|
||||
console.log('CCXT Library current supported exchanges:')
|
||||
@@ -127,15 +113,15 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
console.log('Exchange Class ' + exchangeId)
|
||||
console.log(exchangeClass)
|
||||
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function start(callBackFunction) {
|
||||
try {
|
||||
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
if (TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING === true) {
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
return
|
||||
}
|
||||
|
||||
@@ -149,8 +135,8 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
await getFirstId()
|
||||
await getOHLCVs()
|
||||
if (abort === true) { return }
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
if (TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING === true) {
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
return
|
||||
}
|
||||
await saveOHLCVs()
|
||||
@@ -162,19 +148,21 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
let reportKey;
|
||||
|
||||
reportKey = "Masters" + "-" + "Exchange-Raw-Data" + "-" + "Historic-OHLCVs"
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getContextVariables -> reportKey = " + reportKey)
|
||||
|
||||
if (statusDependencies.statusReports.get(reportKey).status === "Status Report is corrupt.") {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey)
|
||||
|
||||
if (thisReport.file.beginingOfMarket !== undefined) { // This means this is not the first time this process run.
|
||||
beginingOfMarket = new Date(thisReport.file.beginingOfMarket.year + "-" + thisReport.file.beginingOfMarket.month + "-" + thisReport.file.beginingOfMarket.days + " " + thisReport.file.beginingOfMarket.hours + ":" + thisReport.file.beginingOfMarket.minutes + GMT_SECONDS);
|
||||
lastFile = new Date(thisReport.file.lastFile.year + "-" + thisReport.file.lastFile.month + "-" + thisReport.file.lastFile.days + " " + thisReport.file.lastFile.hours + ":" + thisReport.file.lastFile.minutes + GMT_SECONDS);
|
||||
beginingOfMarket = new Date(thisReport.file.beginingOfMarket.year + "-" + thisReport.file.beginingOfMarket.month + "-" + thisReport.file.beginingOfMarket.days + " " + thisReport.file.beginingOfMarket.hours + ":" + thisReport.file.beginingOfMarket.minutes + TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
lastFile = new Date(thisReport.file.lastFile.year + "-" + thisReport.file.lastFile.month + "-" + thisReport.file.lastFile.days + " " + thisReport.file.lastFile.hours + ":" + thisReport.file.lastFile.minutes + TS.projects.superalgos.globals.timeConstants.GMT_SECONDS);
|
||||
lastId = thisReport.file.lastId
|
||||
lastCandleOfTheDay = thisReport.file.lastCandleOfTheDay
|
||||
} else { // This means this is the first time this process run.
|
||||
@@ -207,12 +195,15 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.stack);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getContextVariables -> err = " + err.stack);
|
||||
if (err.message === "Cannot read property 'file' of undefined") {
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot Status Dependencies. ");
|
||||
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Check the bot Status Dependencies. ");
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
|
||||
}
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
abort = true
|
||||
}
|
||||
}
|
||||
@@ -258,15 +249,16 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
/* Reporting we are doing well */
|
||||
function heartBeat(noNewInternalLoop) {
|
||||
let processingDate = new Date(since)
|
||||
processingDate = processingDate.getUTCFullYear() + '-' + utilities.pad(processingDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(processingDate.getUTCDate(), 2);
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getOHLCVs -> Fetching OHLCVs @ " + processingDate + "-> exchange = " + bot.exchange + " -> symbol = " + symbol + " -> since = " + since + " -> limit = " + limit) }
|
||||
let heartBeatText = "Fetching " + allOHLCVs.length.toFixed(0) + " OHLCVs from " + bot.exchange + " " + symbol + " @ " + processingDate
|
||||
processingDate = processingDate.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processingDate.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processingDate.getUTCDate(), 2);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getOHLCVs -> Fetching OHLCVs @ " + processingDate + "-> exchange = " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + " -> symbol = " + symbol + " -> since = " + since + " -> limit = " + limit)
|
||||
let heartBeatText = "Fetching " + allOHLCVs.length.toFixed(0) + " OHLCVs from " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + " " + symbol + " @ " + processingDate
|
||||
let currentDate = new Date(since)
|
||||
let percentage = global.getPercentage(fromDate, currentDate, lastDate)
|
||||
bot.processHeartBeat(heartBeatText, percentage) // tell the world we are alive and doing well
|
||||
if (global.areEqualDates(currentDate, new Date()) === false) {
|
||||
let percentage = TS.projects.superalgos.utilities.dateTimeFunctions.getPercentage(fromDate, currentDate, lastDate)
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, heartBeatText, percentage) // tell the world we are alive and doing well
|
||||
if (TS.projects.superalgos.utilities.dateTimeFunctions.areTheseDatesEqual(currentDate, new Date()) === false) {
|
||||
if (noNewInternalLoop !== true) {
|
||||
logger.newInternalLoop(bot.codeName, bot.process, currentDate, percentage);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.newInternalLoop(currentDate, percentage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -304,18 +296,21 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
]
|
||||
*/
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getOHLCVs -> OHLCVs Fetched = " + OHLCVs.length) }
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getOHLCVs -> OHLCVs Fetched = " + OHLCVs.length)
|
||||
if (OHLCVs.length > 0) {
|
||||
let beginDate = new Date(OHLCVs[0].timestamp)
|
||||
let endDate = new Date(OHLCVs[OHLCVs.length - 1].timestamp)
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getOHLCVs -> OHLCVs Fetched From " + beginDate + " -> timestamp = " + OHLCVs[0].timestamp) }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getOHLCVs -> OHLCVs Fetched to " + endDate + " -> timestamp = " + OHLCVs[OHLCVs.length - 1].timestamp) }
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getOHLCVs -> OHLCVs Fetched From " + beginDate + " -> timestamp = " + OHLCVs[0].timestamp)
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> getOHLCVs -> OHLCVs Fetched to " + endDate + " -> timestamp = " + OHLCVs[OHLCVs.length - 1].timestamp)
|
||||
|
||||
if (fisrtTimeThisProcessRun === true) {
|
||||
let OHLCV = OHLCVs[0]
|
||||
|
||||
initialProcessTimestamp = OHLCV[0] // 'timestamp'
|
||||
beginingOfMarket = new Date(Math.trunc(OHLCV[0] / ONE_DAY) * ONE_DAY) // 'timestamp'
|
||||
beginingOfMarket = new Date(Math.trunc(OHLCV[0] / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) * TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) // 'timestamp'
|
||||
fromDate = new Date(beginingOfMarket.valueOf())
|
||||
fisrtTimeThisProcessRun = false
|
||||
}
|
||||
@@ -347,7 +342,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
|
||||
if (
|
||||
OHLCVs.length < limit - 1 ||
|
||||
global.STOP_TASK_GRACEFULLY === true ||
|
||||
TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING === true ||
|
||||
allOHLCVs.length >= MAX_OHLCVs_PER_EXECUTION
|
||||
) {
|
||||
break
|
||||
@@ -355,22 +350,26 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.stack.toString().indexOf('ERR_RATE_LIMIT') >= 0) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getOHLCVs -> Retrying Later -> The Exchange " + bot.exchange + " is saying you are requesting data too often. I will retry the request later, no action is required. To avoid this happening again please increase the rateLimit at the Exchange node config. You might continue seeing this if you are retrieving data from multiple markets at the same time. In this case I tried to get 1 min OHLCVs from " + symbol);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getOHLCVs -> Retrying Later -> The Exchange " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + " is saying you are requesting data too often. I will retry the request later, no action is required. To avoid this happening again please increase the rateLimit at the Exchange node config. You might continue seeing this if you are retrieving data from multiple markets at the same time. In this case I tried to get 1 min OHLCVs from " + symbol);
|
||||
return
|
||||
}
|
||||
|
||||
if (err.stack.toString().indexOf('RequestTimeout') >= 0) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getOHLCVs -> Retrying Later -> The Exchange " + bot.exchange + " is not responding at the moment. I will save the data already fetched and try to reconnect later to fetch the rest of the missing data.");
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getOHLCVs -> Retrying Later -> The Exchange " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + " is not responding at the moment. I will save the data already fetched and try to reconnect later to fetch the rest of the missing data.");
|
||||
return
|
||||
}
|
||||
|
||||
if (err.stack.toString().indexOf('ExchangeNotAvailable') >= 0) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getOHLCVs -> Retrying Later -> The Exchange " + bot.exchange + " is not available at the moment. I will save the data already fetched and try to reconnect later to fetch the rest of the missing data.");
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getOHLCVs -> Retrying Later -> The Exchange " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + " is not available at the moment. I will save the data already fetched and try to reconnect later to fetch the rest of the missing data.");
|
||||
return
|
||||
}
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> getOHLCVs -> Retrying Later -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> getOHLCVs -> Retrying Later -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE);
|
||||
abort = true
|
||||
return
|
||||
}
|
||||
@@ -382,8 +381,8 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
|
||||
let candlesFileContent = '['
|
||||
let volumesFileContent = '['
|
||||
let previousDay = Math.trunc((initialProcessTimestamp - ONE_DAY) / ONE_DAY)
|
||||
let currentDay = Math.trunc((initialProcessTimestamp - ONE_DAY) / ONE_DAY)
|
||||
let previousDay = Math.trunc((initialProcessTimestamp - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
let currentDay = Math.trunc((initialProcessTimestamp - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS)
|
||||
let needSeparator = false
|
||||
let error
|
||||
let separator
|
||||
@@ -424,37 +423,38 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
for (let j = 0; j < 60 * 24; j++) {
|
||||
|
||||
let candle = {
|
||||
begin: currentDay * ONE_DAY + ONE_MIN * j,
|
||||
end: currentDay * ONE_DAY + ONE_MIN * j + ONE_MIN - 1,
|
||||
begin: currentDay * TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS + TS.projects.superalgos.globals.timeConstants.ONE_MIN_IN_MILISECONDS * j,
|
||||
end: currentDay * TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS + TS.projects.superalgos.globals.timeConstants.ONE_MIN_IN_MILISECONDS * j + TS.projects.superalgos.globals.timeConstants.ONE_MIN_IN_MILISECONDS - 1,
|
||||
open: lastCandle.close,
|
||||
close: lastCandle.close,
|
||||
min: lastCandle.close,
|
||||
max: lastCandle.close
|
||||
}
|
||||
let volume = {
|
||||
begin: currentDay * ONE_DAY + ONE_MIN * j,
|
||||
end: currentDay * ONE_DAY + ONE_MIN * j + ONE_MIN - 1,
|
||||
begin: currentDay * TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS + TS.projects.superalgos.globals.timeConstants.ONE_MIN_IN_MILISECONDS * j,
|
||||
end: currentDay * TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS + TS.projects.superalgos.globals.timeConstants.ONE_MIN_IN_MILISECONDS * j + TS.projects.superalgos.globals.timeConstants.ONE_MIN_IN_MILISECONDS - 1,
|
||||
buy: lastVolume.buy,
|
||||
sell: lastVolume.sell
|
||||
}
|
||||
|
||||
let processingDate = new Date(candle.begin)
|
||||
processingDate = processingDate.getUTCFullYear() + '-' + utilities.pad(processingDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(processingDate.getUTCDate(), 2);
|
||||
processingDate = processingDate.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processingDate.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processingDate.getUTCDate(), 2);
|
||||
|
||||
if (candle.begin > (new Date()).valueOf()) {
|
||||
/* We stop when the current candle is pointing to a time in the future.*/
|
||||
headOfTheMarketReached = true
|
||||
saveFile(currentDay)
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> saveOHLCVs -> Before Fetch -> Saving OHLCVs @ " + processingDate + " -> i = " + i + " -> total = " + allOHLCVs.length) }
|
||||
bot.processHeartBeat("Saving " + i.toFixed(0) + " / " + allOHLCVs.length + " OHLCVs from " + bot.exchange + " " + symbol + " @ " + processingDate) // tell the world we are alive and doing well
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> saveOHLCVs -> Before Fetch -> Saving OHLCVs @ " + processingDate + " -> i = " + i + " -> total = " + allOHLCVs.length)
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, "Saving " + i.toFixed(0) + " / " + allOHLCVs.length + " OHLCVs from " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + " " + symbol + " @ " + processingDate) // tell the world we are alive and doing well
|
||||
|
||||
/* We exit the loop and we aint comming back*/
|
||||
return
|
||||
}
|
||||
|
||||
let OHLCV = { // these values should be overrided unless there are no OHLVCs fetched from the exchange.
|
||||
timestamp: (new Date()).valueOf() + ONE_MIN,
|
||||
timestamp: (new Date()).valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_MIN_IN_MILISECONDS,
|
||||
open: 0,
|
||||
hight: 0,
|
||||
low: 0,
|
||||
@@ -475,7 +475,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
}
|
||||
}
|
||||
|
||||
let candleMinute = Math.trunc(candle.begin / ONE_MIN)
|
||||
let candleMinute = Math.trunc(candle.begin / TS.projects.superalgos.globals.timeConstants.ONE_MIN_IN_MILISECONDS)
|
||||
let OHLCVMinute
|
||||
|
||||
checkOHLCVMinute()
|
||||
@@ -486,7 +486,7 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
UTC minute. It is also not guaranteed that the distance between timestamps will be the same. To fix this, we will do this.
|
||||
*/
|
||||
|
||||
OHLCVMinute = Math.trunc(OHLCV.timestamp / ONE_MIN)
|
||||
OHLCVMinute = Math.trunc(OHLCV.timestamp / TS.projects.superalgos.globals.timeConstants.ONE_MIN_IN_MILISECONDS)
|
||||
|
||||
if (OHLCVMinute < candleMinute) {
|
||||
if (i >= allOHLCVs.length - 1) {
|
||||
@@ -513,8 +513,9 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
heartBeatCounter--
|
||||
if (heartBeatCounter <= 0) {
|
||||
heartBeatCounter = 1440
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> saveOHLCVs -> After Fetch -> Saving OHLCVs @ " + processingDate + " -> i = " + i + " -> total = " + allOHLCVs.length) }
|
||||
bot.processHeartBeat("Saving " + i.toFixed(0) + " / " + allOHLCVs.length + " OHLCVs from " + bot.exchange + " " + symbol + " @ " + processingDate) // tell the world we are alive and doing well
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> saveOHLCVs -> After Fetch -> Saving OHLCVs @ " + processingDate + " -> i = " + i + " -> total = " + allOHLCVs.length)
|
||||
TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, "Saving " + i.toFixed(0) + " / " + allOHLCVs.length + " OHLCVs from " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + " " + symbol + " @ " + processingDate) // tell the world we are alive and doing well
|
||||
}
|
||||
/* End Reporting */
|
||||
|
||||
@@ -568,10 +569,10 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
let fileName = 'Data.json'
|
||||
|
||||
filesToCreate++
|
||||
fileStorage.createTextFile(getFilePath(day * ONE_DAY, CANDLES_FOLDER_NAME) + '/' + fileName, candlesFileContent + '\n', onFileCreated);
|
||||
fileStorage.createTextFile(getFilePath(day * TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS, CANDLES_FOLDER_NAME) + '/' + fileName, candlesFileContent + '\n', onFileCreated);
|
||||
|
||||
filesToCreate++
|
||||
fileStorage.createTextFile(getFilePath(day * ONE_DAY, VOLUMES_FOLDER_NAME) + '/' + fileName, volumesFileContent + '\n', onFileCreated);
|
||||
fileStorage.createTextFile(getFilePath(day * TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS, VOLUMES_FOLDER_NAME) + '/' + fileName, volumesFileContent + '\n', onFileCreated);
|
||||
|
||||
candlesFileContent = '['
|
||||
volumesFileContent = '['
|
||||
@@ -580,13 +581,14 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
}
|
||||
|
||||
function onFileCreated(err) {
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> OHLCVsReadyToBeSaved -> onFileBCreated -> err = " + JSON.stringify(err));
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> OHLCVsReadyToBeSaved -> onFileBCreated -> err = " + JSON.stringify(err));
|
||||
error = err // This allows the loop to be breaked.
|
||||
return;
|
||||
}
|
||||
filesCreated++
|
||||
lastFile = new Date((currentDay * ONE_DAY))
|
||||
lastFile = new Date((currentDay * TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS))
|
||||
if (filesCreated === filesToCreate) {
|
||||
controlLoop()
|
||||
}
|
||||
@@ -595,16 +597,16 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
function getFilePath(timestamp, folderName) {
|
||||
let datetime = new Date(timestamp)
|
||||
let dateForPath = datetime.getUTCFullYear() + '/' +
|
||||
utilities.pad(datetime.getUTCMonth() + 1, 2) + '/' +
|
||||
utilities.pad(datetime.getUTCDate(), 2)
|
||||
let filePath = bot.filePathRoot + "/Output/" + folderName + '/' + dateForPath;
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(datetime.getUTCMonth() + 1, 2) + '/' +
|
||||
TS.projects.superalgos.utilities.miscellaneousFunctions.pad(datetime.getUTCDate(), 2)
|
||||
let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + folderName + '/' + dateForPath;
|
||||
return filePath
|
||||
}
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
if (TS.projects.superalgos.globals.taskVariables.IS_TASK_STOPPING === true) {
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
return
|
||||
}
|
||||
|
||||
@@ -622,7 +624,8 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
|
||||
if (i >= allOHLCVs.length - 1) {
|
||||
writeStatusReport()
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> saveOHLCVs -> controlLoop -> Exit because i reached the end of the candles array. ") }
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> saveOHLCVs -> controlLoop -> Exit because i reached the end of the candles array. ")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -631,14 +634,16 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
if (headOfTheMarketReached === false) {
|
||||
setImmediate(loop)
|
||||
} else {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> saveOHLCVs -> controlLoop -> Exit because we reached the end of the market. ") }
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[INFO] start -> saveOHLCVs -> controlLoop -> Exit because we reached the end of the market. ")
|
||||
writeStatusReport()
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> saveOHLCVs -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> saveOHLCVs -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
abort = true
|
||||
}
|
||||
}
|
||||
@@ -672,23 +677,26 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
|
||||
thisReport.save(onSaved);
|
||||
|
||||
function onSaved(err) {
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> onSaved -> err = " + err.stack);
|
||||
if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeStatusReport -> onSaved -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> writeStatusReport -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME,
|
||||
"[ERROR] start -> err = " + err.stack);
|
||||
callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
.git
|
||||
.dockerignore
|
||||
Dockerfile
|
||||
node_modules
|
||||
*.swp
|
||||
*.pyc
|
||||
@@ -0,0 +1,4 @@
|
||||
*.* text eol=lf
|
||||
php/test/*.php linguist-generated=true
|
||||
python/ccxt/*.py linguist-generated=true
|
||||
python/ccxt/__init__.py linguist-generated=false
|
||||
@@ -0,0 +1,926 @@
|
||||
# Contributing To The CCXT Library
|
||||
|
||||
- [How To Submit A Question Or Issue](#how-to-submit-an-issue)
|
||||
- [How To Contribute Code](#how-to-contribute-code)
|
||||
- [What You Need To Have](#what-you-need-to-have)
|
||||
- [What You Need To Know](#what-you-need-to-know)
|
||||
|
||||
## How To Submit An Issue
|
||||
|
||||
If you want to submit an issue and you want your issue to be resolved quickly, here's a checklist for you:
|
||||
|
||||
- Read the [Manual](https://github.com/ccxt/ccxt/wiki/Manual), and especially carefully read the following sections:
|
||||
- [Exchange Properties](https://github.com/ccxt/ccxt/wiki/Manual#exchange-properties)
|
||||
- [Rate Limit](https://github.com/ccxt/ccxt/wiki/Manual#rate-limit)
|
||||
- [DDoS Protection](https://github.com/ccxt/ccxt/wiki/Manual#ddos-protection-by-cloudflare--incapsula)
|
||||
- [Authentication](https://github.com/ccxt/ccxt/wiki/Manual#authentication)
|
||||
- [API Keys Setup](https://github.com/ccxt/ccxt/wiki/Manual#api-keys-setup)
|
||||
- Read the [Troubleshooting](https://github.com/ccxt/ccxt/wiki/Manual#troubleshooting) section and follow troubleshooting steps.
|
||||
- Read the [FAQ](https://github.com/ccxt/ccxt/wiki/FAQ) for most frequently asked questions.
|
||||
- Read the [API docs](https://github.com/ccxt/ccxt/wiki/Exchange-Markets) for your exchange.
|
||||
- Search for similar issues first to avoid duplicates.
|
||||
- If your issue is unique, along with a basic description of the failure, the following **IS REQUIRED**:
|
||||
- **set `exchange.verbose = true` property on the exchange instance before calling its functions or methods**
|
||||
- **DON'T POST SCREENSHOTS OF CODE OR ERRORS, POST THE OUTPUT AND CODE IN PLAIN TEXT!**
|
||||
- **surround code and output with triple backticks: ```GOOD```**
|
||||
- don't confuse the backtick symbol (`) with the quote symbol (\'): '''BAD'''
|
||||
- don't confuse a single backtick with triple backticks: `BAD`
|
||||
- paste a complete code snippet you're having difficulties with, avoid one-liners
|
||||
- paste the **full verbose output** of the failing method without your keys
|
||||
- the verbose output should include the request and response from the exchange (not just an error callstack)
|
||||
- write your language **and version**
|
||||
- write ccxt library version
|
||||
- which exchange it is
|
||||
- which method you're trying to call
|
||||
|
||||
### Reporting Vulnerabilities And Critical Issues
|
||||
|
||||
If you found a security issue or a critical vulnerability and reporting it in public would impose risk – please feel free to send us a message to <a href="mailto:info@ccxt.trade">info@ccxt.trade</a>.
|
||||
|
||||
## How To Contribute Code
|
||||
|
||||
- **[MAKE SURE YOUR CODE IS UNIFIED](https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#derived-exchange-classes)!**
|
||||
|
||||
↑ This is the most important rule of all.
|
||||
|
||||
- **PLEASE, DO NOT COMMIT THE FOLLOWING FILES IN PULL REQUESTS:**
|
||||
|
||||
- `/doc/*` (these files are generated from `/wiki/*`, place your edits there)
|
||||
- `/build/*` (these are generated automatically)
|
||||
- `/php/*` (except for base classes)
|
||||
- `/python/*` (except for base classes)
|
||||
- `/ccxt.js`
|
||||
- `/README.md` (exchange lists are generated automatically)
|
||||
- `/package.json`
|
||||
- `/package.lock`
|
||||
- `/wiki/*` (except for real edits, exchange lists are generated automatically)
|
||||
- `/dist/ccxt.browser.js` (this is also browserified automatically)
|
||||
|
||||
|
||||
These files are generated ([explained below](https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#multilanguage-support)) and will be overwritten upon build. Please don't commit them to avoid bloating the repository which is already quite large. Most often, you have to commit just one single source file to submit an edit to the implementation of an exchange.
|
||||
|
||||
- **PLEASE, SUBMIT ATOMIC EDITS, ONE PULL REQUEST PER ONE EXCHANGE, DO NOT MIX THEM**
|
||||
- **MAKE SURE YOUR CODE PASSES ALL SYNTAX CHECKS BY RUNNING `npm run build`**
|
||||
|
||||
## Pending Tasks
|
||||
|
||||
Below is a list of functionality we would like to have implemented and fully **unified** in the library in the first place at this time. Most of these tasks are already in progress, implemented for some exchanges, but not all of them:
|
||||
|
||||
- Margin trading
|
||||
- Leverage
|
||||
- Derivatives (futures, options)
|
||||
- Main account / subaccounts
|
||||
- Conditional orders (stop loss, take profit)
|
||||
- `transfer` between subaccounts and main account
|
||||
- `fetchTransfer`
|
||||
- `fetchTransfers`
|
||||
- `fetchLedger`
|
||||
- `fetchPositions`
|
||||
- `closePosition`
|
||||
- `closePositions`
|
||||
|
||||
If you want to contribute by submitting partial implementations be sure to look up examples of how it's done inside the library (where implemented already) and copy the adopted practices.
|
||||
|
||||
If your proposal, suggestion or improvement does not relate to the above list of tasks before submitting it make sure it is:
|
||||
1. really needed by the majority of ccxt users
|
||||
2. designed to be a general-purpose solution, not hardcoded for your specific needs
|
||||
3. done in a generalized way compatible with all exchanges (not exchange-specific)
|
||||
4. portable (available in all supported languages)
|
||||
5. robust
|
||||
6. explicit in what it's doing
|
||||
7. doesn't break anything (if you change a method, make sure that all other methods calling the edited method are not broken)
|
||||
|
||||
The following is a set of rules for contributing to the ccxt library codebase.
|
||||
|
||||
## What You Need To Have
|
||||
|
||||
If you're not going to develop CCXT and contribute code to the CCXT library, then you don't need the Docker image nor the CCXT repository. If you just want to use CCXT inside your project simply install it as a regular package into the project folder as documented in the Manual (https://github.com/ccxt/ccxt/wiki/Install):
|
||||
|
||||
- [JavaScript / Node.js / NPM](https://github.com/ccxt/ccxt/wiki/Install#javascript-npm)
|
||||
|
||||
```shell
|
||||
# JavaScript / Node.js / NPM
|
||||
npm install ccxt
|
||||
```
|
||||
|
||||
- [Python / PIP](https://github.com/ccxt/ccxt/wiki/Install#python)
|
||||
|
||||
```shell
|
||||
# Python
|
||||
pip install ccxt # or pip3 install ccxt
|
||||
```
|
||||
|
||||
- [PHP / Composer](https://github.com/ccxt/ccxt/wiki/Install#php)
|
||||
|
||||
```shell
|
||||
# PHP / Composer
|
||||
composer install ccxt
|
||||
```
|
||||
|
||||
### With Docker
|
||||
|
||||
The easiest way is to use Docker to run an isolated build & test enviroment with all the dependencies installed:
|
||||
|
||||
```shell
|
||||
docker-compose run --rm ccxt
|
||||
```
|
||||
|
||||
That builds a container and opens a shell, where the `npm run build` and `node run-tests` commands should simply work out of the box.
|
||||
|
||||
The CCXT folder is mapped inside of the container, except the `node_modules` folder — the container would have its own ephemeral copy — so that won't mess up your locally installed modules. This means that you can edit sources on your host machine using your favorite editor and build/test them in the running container.
|
||||
|
||||
This way you can keep the build tools and processes isolated, not having to work through the painful process of installing all those dependencies to your host machine manually.
|
||||
|
||||
### Without Docker
|
||||
|
||||
#### Dependencies
|
||||
|
||||
- Git
|
||||
- [Node.js](https://nodejs.org/en/download/) 8+
|
||||
- [Python](https://www.python.org/downloads/) 3.5.3+
|
||||
- requests (`pip install requests`)
|
||||
- [aiohttp](https://docs.aiohttp.org/) (`pip install aiohttp`)
|
||||
- [tox](https://tox.readthedocs.io)
|
||||
- via pip: `pip install tox`
|
||||
- MacOS with [brew](https://brew.sh): `brew install tox`
|
||||
- Ubuntu Linux: `apt-get install tox`
|
||||
- [PHP](https://secure.php.net/downloads.php) 5.3+ with the following extensions installed and enabled:
|
||||
- cURL
|
||||
- iconv
|
||||
- mbstring
|
||||
- PCRE
|
||||
- bcmath (php<7.1)
|
||||
|
||||
#### Build Steps
|
||||
|
||||
```shell
|
||||
git clone https://github.com/ccxt/ccxt.git
|
||||
```
|
||||
|
||||
```shell
|
||||
cd ccxt
|
||||
```
|
||||
|
||||
```shell
|
||||
npm install
|
||||
```
|
||||
|
||||
```shell
|
||||
npm run build
|
||||
```
|
||||
|
||||
## What You Need To Know
|
||||
|
||||
### Repository Structure
|
||||
|
||||
The contents of the repository are structured as follows:
|
||||
|
||||
```shell
|
||||
/ # root directory aka npm module/package folder for Node.js
|
||||
/.babelrc # babel config used for making the ES5 version of the library
|
||||
/.eslintrc # linter
|
||||
/.gitattributes # contains linguist settings for language detection in repo
|
||||
/.gitignore # ignore it
|
||||
/.npmignore # files to exclude from the NPM package
|
||||
/.travis.yml # a YAML config for travis-ci (continuous integration)
|
||||
/CONTRIBUTING.md # this file
|
||||
/LICENSE.txt # MIT
|
||||
/README.md # master markdown for GitHub, npmjs.com, npms.io, yarn and others
|
||||
/build/ # build scripts
|
||||
/build/export-exchanges.js # used to create tables of exchanges in the docs during the build
|
||||
/build/transpile.js # the transpilation script
|
||||
/build/update-badges.js # a JS script to update badges in the README and in docs
|
||||
/build/vss.js # reads single-sourced version from package.json and writes it everywhere
|
||||
/dist/ # a folder for the generated browser bundle of CCXT
|
||||
/ccxt.js # entry point for the master JS version of the ccxt library
|
||||
/ccxt.php # entry point for the PHP version of the ccxt library
|
||||
/doc/ # Sphinx-generated rst-docs for http://ccxt.readthedocs.io/
|
||||
/js/ # the JS version of the library
|
||||
/php/ # PHP ccxt module/package folder
|
||||
/python/ # Python ccxt module/package folder for PyPI
|
||||
/python/__init__.py # entry point for the Python version of the ccxt.library
|
||||
/python/async_support/ # asynchronous version of the ccxt.library for Python 3.5.3+ asyncio
|
||||
/python/base/ # base code for the Python version of the ccxt library
|
||||
/python/MANIFEST.in # a PyPI-package file listing extra package files (license, configs, etc...)
|
||||
/python/README.md # a copy of README.md for PyPI
|
||||
/python/setup.cfg # wheels config file for the Python package
|
||||
/python/setup.py # pip/setuptools script (build/install) for ccxt in Python
|
||||
/python/tox.ini # tox config for Python
|
||||
/examples/ # self-explanatory
|
||||
/examples/js # ...
|
||||
/examples/php # ...
|
||||
/examples/py # ...
|
||||
/exchanges.cfg # custom bundle config for including only the exchanges you need
|
||||
/package.json # npm package file, also used in setup.py for version single-sourcing
|
||||
/run-tests.js # a front-end to run individual tests of all exchanges in all languages (JS/PHP/Python)
|
||||
/wiki/ # the source of all docs (edits go here)
|
||||
```
|
||||
|
||||
### Multilanguage Support
|
||||
|
||||
The ccxt library is available in three different languages (more to come). We encourage developers to design *portable* code, so that a single-language user could read the code in other languages and understand it easily. This helps the adoption of the library. The main goal is to provide a generalized, unified, consistent and robust interface to as many existing cryptocurrency exchanges as possible.
|
||||
|
||||
At first, all language-specific versions were developed in parallel, but separately from each other. But when it became too hard to maintain and keep the code consistent among all supported languages we have decided to switch to what we call a *source/generated* process. There is now a single source version in one language, that is JavaScript. Other language-specific versions are syntactically derived (transpiled, generated) automatically from the source version. But it doesn't mean that you have to be a JS coder to contribute. The portability principle allows Python and PHP devs to effectively participate in developing the source version as well.
|
||||
|
||||
The module entry points are:
|
||||
- `./python/__init__.py` for the Python pip package
|
||||
- `./python/async/__init__.py` for the Python 3.5.3+ ccxt.async_support subpackage
|
||||
- `./ccxt.js` for the Node.js npm package
|
||||
- `./dist/ccxt.browser.js` for the browser bundle
|
||||
- `./ccxt.php` for PHP
|
||||
|
||||
Generated versions and docs are transpiled from the source `ccxt.js` file and files in `./js/` by the `npm run build` command.
|
||||
|
||||
### Transpiled (generated) files
|
||||
|
||||
- All derived exchange classes are transpiled automatically from source JS files. The source files are language-agnostic, easily mapped line-to-line to any other language and written in a cross-language-compatible way. Any coder can read it (by design).
|
||||
- All base classes are **not** transpiled, those are language-specific.
|
||||
|
||||
#### JavaScript
|
||||
|
||||
The `ccxt.browser.js` is generated with Babel from source.
|
||||
|
||||
#### Python
|
||||
|
||||
These files containing derived exchange classes are transpiled from JS into Python:
|
||||
|
||||
- `js/[_a-z].js` → `python/ccxt/async/[_a-z].py`
|
||||
- `python/ccxt/async[_a-z].py` → `python/ccxt/[_a-z].py` (Python 3 asyncio → Python 2 sync transpilation stage)
|
||||
- `python/test/test_async.py` → `python/test/test.py` (the sync test is generated from the async test)
|
||||
|
||||
These Python base classes and files are not transpiled:
|
||||
|
||||
- `python/ccxt/base/*`
|
||||
- `python/ccxt/async/base/*`
|
||||
|
||||
#### PHP
|
||||
|
||||
These files containing derived exchange classes are transpiled from JS into PHP:
|
||||
|
||||
- `js/[_a-z].js` → `php/[_a-z].php`
|
||||
|
||||
These PHP base classes and files are not transpiled:
|
||||
|
||||
- `php/base/*`
|
||||
|
||||
#### Typescript
|
||||
|
||||
- `js/[_a-z].js` → `ccxt.d.ts`
|
||||
|
||||
### Base Class
|
||||
|
||||
```UNDER CONSTRUCTION```
|
||||
|
||||
### Derived Exchange Classes
|
||||
|
||||
Transpiler is regex-based and heavily relies on specific formatting rules. If you break them then the transpiler will either
|
||||
fail to generate Python/PHP classes at all or will generate malformed Python/PHP syntax.
|
||||
|
||||
Below are key notes on how to keep the JS code transpileable.
|
||||
|
||||
Use the linter `npm run lint js/your-exchange-implementation.js` before you build. It will cover many (but not all) the issues,
|
||||
so manual checking will still be required if transpilation fails.
|
||||
|
||||
If you see a `[TypeError] Cannot read property '1' of null` exception or any other transpilation error when you `npm run build`, check if your code satisfies the following rules:
|
||||
|
||||
- don't put empty lines inside your methods
|
||||
- always use Python-style indentation, it is preserved as is for all languages
|
||||
- indent with 4 spaces **exactly**, avoid tabs
|
||||
- put an empty line between each of your methods
|
||||
- avoid mixed comment styles, use double-slash `//` in JS for line comments
|
||||
- avoid multi-line comments
|
||||
|
||||
If the transpiling process finishes successfully, but generates incorrect Python/PHP syntax, check for the following:
|
||||
|
||||
- every opening bracket like `(` or `{` should have a space before it!
|
||||
- do not use language-specific code syntax sugar, even if you really want to
|
||||
- unfold all maps and comprehensions to basic for-loops
|
||||
- don't change the arguments of overridden inherited methods, keep them uniform across all exchanges
|
||||
- do everything with base class methods only (for example, use `this.json ()` for converting objects to json).
|
||||
- always put a semicolon `;` at the end of each statement, as in PHP/C-style
|
||||
- all associative keys must be single-quoted strings everywhere, `array['good'], array.bad`
|
||||
- variables should be declared with `const` or `let` keywords semantically (no `var`!), prefer `const` everywhere
|
||||
|
||||
And structurally:
|
||||
|
||||
- if you need another base method you will have to implement it in all three languages
|
||||
- do not issue more than one HTTP request from a unified method
|
||||
- try to reduce syntax to basic one-liner expressions
|
||||
- multiple lines are ok, but you should avoid deep nesting with lots of brackets
|
||||
- avoid changing the contents of the arguments and params passed by reference into function calls
|
||||
- do not use conditional statements that are too complex (heavy if-bracketing)
|
||||
- do not use heavy ternary conditionals
|
||||
- avoid operators clutter (**don't do this**: `a && b || c ? d + 80 : e ** f`)
|
||||
- do not use `.includes()`, use `.indexOf()` instead!
|
||||
- never use `.toString()` on floats: `Number (0.00000001).toString () === '1e-8'`
|
||||
- do not use closures, `a.map` or `a.filter (x => (x === 'foobar'))` is not acceptable in derived classes
|
||||
- do not use the `in` operator to check if a value is in a non-associative array (list)
|
||||
- don't add custom currency or symbol/pair conversions and formatting, copy from existing code instead
|
||||
- **don't access non-existent keys, `array['key'] || {}` won't work in other languages!**
|
||||
- keep it simple, don't do more than one statement in one line
|
||||
|
||||
#### Sending Market Ids
|
||||
|
||||
Most of exchanges' API endpoints will require an exchange-specific market symbol or trading pair or instrument to be specified in the request.
|
||||
|
||||
**We don't send unified symbols to exchanges directly!** They are not interchangeable! There is a significant difference between *exchange-specific market-ids* and *unified symbols*! This is explained in the Manual, here:
|
||||
|
||||
- https://github.com/ccxt/ccxt/wiki/Manual#markets
|
||||
- https://github.com/ccxt/ccxt/wiki/Manual#symbols-and-market-ids
|
||||
|
||||
**NEVER DO THIS:**
|
||||
|
||||
```JavaScript
|
||||
async fetchTicker (symbol, params = {}) {
|
||||
const request = {
|
||||
'pair': symbol, // very bad, sending unified symbols to the exchange directly
|
||||
};
|
||||
const response = await this.publicGetEndpoint (request);
|
||||
// parse in a unified way...
|
||||
}
|
||||
```
|
||||
|
||||
**DO NOT DO THIS EITHER:**
|
||||
|
||||
```JavaScript
|
||||
async fetchTicker (symbol, params = {}) {
|
||||
const request = {
|
||||
'symbol': symbol, // very bad, sending unified symbols to the exchange directly
|
||||
};
|
||||
const response = await this.publicGetEndpoint (request);
|
||||
// parse in a unified way...
|
||||
}
|
||||
```
|
||||
|
||||
Instead of sending a unified CCXT symbol to the exchange, we **always** take the exchange-specific market-`id` that corresponds to that symbol. If it so happens that an exchange specific market-id is exactly the same as the CCXT unified symbol – that's a happy coincidence, but we never rely on that in the unified CCXT API.
|
||||
|
||||
To get the exchange-specific market-id by a unified CCXT symbol, use the following methods:
|
||||
|
||||
- `this.market (symbol)` – returns the entire unified market structure, containing the `id`, `baseId`, `quoteId`, and many other interesting things
|
||||
- `this.marketId (symbol)` – returns just the exchange-specific `id` of a market by a unified symbol (if you don't need anything else)
|
||||
|
||||
**GOOD EXAMPLES:**
|
||||
|
||||
```JavaScript
|
||||
async fetchTicker (symbol, params = {}) {
|
||||
const market = this.market (symbol); // the entire market structure
|
||||
const request = {
|
||||
'pair': market['id'], // good, they may me equal, but often differ, it's ok
|
||||
};
|
||||
const response = await this.publicGetEndpoint (this.extend (request, params));
|
||||
// parse in a unified way...
|
||||
}
|
||||
```
|
||||
|
||||
```JavaScript
|
||||
async fetchTicker (symbol, params = {}) {
|
||||
const marketId = this.marketId (symbol); // just the id
|
||||
const request = {
|
||||
'symbol': marketId, // good, they may me equal, but often differ, it's ok
|
||||
};
|
||||
const response = await this.publicGetEndpoint (this.extend (request, params));
|
||||
// parse in a unified way...
|
||||
}
|
||||
```
|
||||
|
||||
#### Parsing Symbols
|
||||
|
||||
When sending requests to the exchange unified symbols have to be _"converted"_ to exchange-specific market-`id`s like shown above. The same is true on the other side – when receiving an exchange response it has an exchange-specific market-`id` inside it that has to be _"converted back"_ to a unified CCXT symbol.
|
||||
|
||||
**We don't put exchange-specific market-`id`s in unified structures directly!** We can't freely interchange symbols with ids! There is a significant difference between an *exchange-specific market-ids* and *unified symbols*! This is explained in the Manual, here:
|
||||
|
||||
- https://github.com/ccxt/ccxt/wiki/Manual#markets
|
||||
- https://github.com/ccxt/ccxt/wiki/Manual#symbols-and-market-ids
|
||||
|
||||
**NEVER DO THIS:**:
|
||||
|
||||
```JavaScript
|
||||
parseTrade (trade, market = undefined) {
|
||||
// parsing code...
|
||||
return {
|
||||
'info': trade,
|
||||
'symbol': trade['pair'], // very bad, returning exchange-specific market-ids in a unified structure!
|
||||
// other fields...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**DO NOT DO THIS EITHER**
|
||||
|
||||
```JavaScript
|
||||
parseTrade (trade, market = undefined) {
|
||||
// parsing code...
|
||||
return {
|
||||
'info': trade,
|
||||
'symbol': trade['symbol'], // very bad, returning exchange-specific market-ids in a unified structure!
|
||||
// other fields...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
In order to handle the market-`id` properly it has to be looked-up in the info cached on this exchange with `loadMarkets()`:
|
||||
|
||||
**GOOD EXAMPLE:**
|
||||
|
||||
```JavaScript
|
||||
parseTrade (trade, market = undefined) {
|
||||
const marketId = this.safeString (trade, 'pair');
|
||||
// safeSymbol is used to parse the market id to a unified symbol
|
||||
const symbol = this.safeSymbol (marketId, market);
|
||||
return {
|
||||
'info': trade,
|
||||
'symbol': symbol, // very good, a unified symbol here now
|
||||
// other fields...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### Accessing Dictionary Keys
|
||||
|
||||
In JavaScript, dictionary keys can be accessed in two notations:
|
||||
|
||||
- `object['key']` (single-quoted string key notation)
|
||||
- `object.key` (property notation)
|
||||
|
||||
Both work almost identically, and one is implicitly converted to another upon executing the JavaScript code.
|
||||
|
||||
While the above does work in JavaScript, it will not work in Python or PHP. In most languages, associative dictionary keys are not treated in the same way as properties. Therefore, in Python `object.key` is not the same as `object['key']`. In PHP `$object->key` is not the same as `$object['key']` as well. Languages that differentiate between associative keys and properties use different notations for the two.
|
||||
|
||||
To keep the code transpileable, please, remember this simple rule: *always use the single-quoted string key notation `object['key']` for accessing all associative dictionary keys in all languages everywhere throughout this library!*
|
||||
|
||||
#### Sanitizing Input With `safe`-Methods
|
||||
|
||||
JavaScript is less restrictive than other languages. It will tolerate an attempt to dereference a non-existent key where other languages will throw an Exception:
|
||||
|
||||
```JavaScript
|
||||
// JavaScript
|
||||
|
||||
const someObject = {}
|
||||
|
||||
if (someObject['nonExistentKey']) {
|
||||
// the body of this conditional will not execute in JavaScript
|
||||
// because someObject['nonExistentKey'] === undefined === false
|
||||
// but JavaScript will not throw an exception on the if-clause
|
||||
}
|
||||
```
|
||||
|
||||
However, the above logic with *"an undefined value by default"* will not work in Python or PHP.
|
||||
|
||||
```Python
|
||||
# Python
|
||||
some_dictionary = {}
|
||||
|
||||
# breaks
|
||||
if some_dictionary['nonExistentKey']:
|
||||
# in Python the attempt to dereference the nonExistentKey value
|
||||
# will throw a standard built-in KeyError exception
|
||||
|
||||
# works
|
||||
if 'nonExistentKey' in some_dictionary and some_dictionary['nonExistentKey']:
|
||||
# this is a way to check if the key exists before accessing the value
|
||||
|
||||
# also works
|
||||
if some_dictionary.get('nonExistentKey'):
|
||||
# another a way to check if the key exists before accessing the value...
|
||||
```
|
||||
|
||||
Most languages will not tolerate an attempt to access a non-existent key in an object.
|
||||
|
||||
For the above reasons, please, **never do this** in the transpiled JS files:
|
||||
|
||||
```JavaScript
|
||||
// JavaScript
|
||||
const value = object['key'] || other_value; // will not work in Python or PHP!
|
||||
if (object['key'] || other_value) { /* will not work in Python or PHP! */ }
|
||||
```
|
||||
|
||||
Therefore we have a family of `safe*` functions:
|
||||
|
||||
- `safeInteger (object, key)`, `safeInteger2 (object, key1, key2)`
|
||||
- `safeFloat (object, key)`, `safeFloat2 (object, key1, key2)`
|
||||
- `safeString (object, key)`, `safeString2 (object, key1, key2)`
|
||||
- `safeValue (object, key)`, `safeValue2 (object, key1, key2)`
|
||||
|
||||
The `safeValue` function is used for objects inside objects, arrays inside objects and boolean `true/false` values.
|
||||
|
||||
The above safe-functions will check for the existence of the key in the object and will properly return `undefined/None/null` values for JS/Python/PHP. Each function also accepts the default value to be returned instead of `undefined/None/null` in the last argument.
|
||||
|
||||
Alternatively, you could check for the key existence first...
|
||||
|
||||
So, you have to change this:
|
||||
|
||||
```JavaScript
|
||||
if (params['foo'] !== undefined) {
|
||||
}
|
||||
```
|
||||
|
||||
↓
|
||||
|
||||
```JavaScript
|
||||
const foo = this.safeValue (params, 'foo');
|
||||
if (foo !== undefined) {
|
||||
}
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```JavaScript
|
||||
if ('foo' in params) {
|
||||
}
|
||||
```
|
||||
|
||||
#### Using Base Class Cryptography Methods For Authentication
|
||||
|
||||
Do not reinvent the wheel. Always use base-class methods for cryptography.
|
||||
|
||||
The CCXT library supports the following authentication algorithms and cryptography algorithms:
|
||||
|
||||
- HMAC
|
||||
- JWT (JSON Web Token)
|
||||
- RSA
|
||||
- ECDSA Elliptic Curve Cryptography
|
||||
- NIST P256
|
||||
- secp256k1
|
||||
- OTP 2FA (one-time password 2-factor authentication)
|
||||
|
||||
The base `Exchange` class offers several methods that are key to practically all cryptography in this lib. Derived exchange implementations must not use external dependencies for cryptography, everything should be done with base methods only.
|
||||
|
||||
- `hash (message, hash = 'md5', digest = 'hex')`
|
||||
- `hmac (message, secret, hash = 'sha256', digest = 'hex')`
|
||||
- `jwt (message, secret, hash = 'HS256')`
|
||||
- `rsa (message, secret, alg = 'RS256')`
|
||||
- `ecdsa (request, secret, algorithm = 'p256', hash = undefined)`
|
||||
- `totp (secret)`
|
||||
- `stringToBase64()`, `base64ToBinary()`, `binaryToBase64()`...
|
||||
|
||||
The `hash()` method supports the following `hash` algorithms:
|
||||
|
||||
- `'md5'`
|
||||
- `'sha1'`
|
||||
- `'sha3'`
|
||||
- `'sha256'`
|
||||
- `'sha384'`
|
||||
- `'sha512'`
|
||||
- `'keccak'`
|
||||
|
||||
The `digest` encoding argument accepts the following values:
|
||||
|
||||
- `'hex'`
|
||||
- `'binary'`
|
||||
|
||||
The `hmac()` method also supports `'base64'` for the `digest` argument. This is for `hmac()` only, other implementations should use `'binary'` with `binaryToBase64()`.
|
||||
|
||||
#### Timestamps
|
||||
|
||||
**All timestamps throughout all unified structures within this library are integer timestamp _in milliseconds_!**
|
||||
|
||||
In order to convert to milliseconds timestamps, CCXT implements the following methods:
|
||||
|
||||
```JavaScript
|
||||
const data = {
|
||||
'unixTimestampInSeconds': 1565242530,
|
||||
'unixTimestampInMilliseconds': 1565242530165,
|
||||
'stringInSeconds': '1565242530',
|
||||
};
|
||||
|
||||
// convert to integer if the underlying value is already in milliseconds
|
||||
const timestamp = this.safeInteger (data, 'unixTimestampInMilliseconds'); // === 1565242530165
|
||||
|
||||
// convert to integer and multiply by a thousand if the value is a UNIX timestamp in seconds
|
||||
const timestamp = this.safeTimestamp (data, 'unixTimestampInSeconds'); // === 1565242530000
|
||||
|
||||
// convert to integer and multiply by a thousand if the value is in seconds
|
||||
const timestamp = this.safeTimestamp (data, 'stringInSeconds'); // === 1565242530000
|
||||
```
|
||||
|
||||
#### Working With Array Lengths
|
||||
|
||||
In JavaScript the common syntax to get a length of a string or an array is to reference the `.length` property like shown here:
|
||||
|
||||
```JavaScript
|
||||
someArray.length
|
||||
|
||||
// or
|
||||
|
||||
someString.length
|
||||
```
|
||||
|
||||
And it works for both strings and arrays. In Python this is done in a similar way:
|
||||
|
||||
```Python
|
||||
len(some_array)
|
||||
|
||||
# or
|
||||
|
||||
len(some_string)
|
||||
```
|
||||
|
||||
So the length is accessible in the same way for both strings and arrays and both work fine.
|
||||
|
||||
However, with PHP this is different, so the syntax for string lengths and array lengths is different:
|
||||
|
||||
```PHP
|
||||
count(some_array);
|
||||
|
||||
// or
|
||||
|
||||
strlen(some_string); // or mb_strlen
|
||||
```
|
||||
|
||||
Because the transpiler works line-by-line and does no code introspection, it cannot tell arrays from strings and cannot properly transpile `.length` to PHP without additional hinting. It will always transpile JS `.length` to PHP `strlen` and will prefer string lengths over array lengths. In order to indicate an array length properly we have to do the following:
|
||||
|
||||
```JavaScript
|
||||
const arrayLength = someArray.length;
|
||||
// the above line ends with .length;
|
||||
// that ending is a hint for the transpiler that will recognize someArray
|
||||
// as an array variable in this place, rather than a string type variable
|
||||
// now we can use arrayLength for the arithmetic
|
||||
```
|
||||
|
||||
That `.length;` line ending does the trick. The only case when the array `.length` is preferred over the string `.length` is the `for` loop. In the header of the `for` loop, the `.length` always refers to array length (not string length).
|
||||
|
||||
#### Adding Numbers And Concatenating Strings
|
||||
|
||||
In JS the arithmetic addition `+` operator handles both strings and numbers. So, it can concatenate strings with `+` and can sum up numbers with `+` as well. The same is true with Python. With PHP this is different, so it has different operators for string concatenation (the "dot" operator `.`) and for arithmetic addition (the "plus" operator `+`). Once again, because the transpiler does no code introspection it cannot tell if you're adding up numbers or strings in JS. This works fine until you want to transpile this to other languages, be it PHP or whatever other language it is. In order to help the transpiler we have to use `this.sum` for arithmetic additions.
|
||||
|
||||
The rule of thumb is: **`+` is for string concatenation only (!)** and **`this.sum (a, b, c, ...)` is for arithmetic additions**. The same logic applies to operator `+=` vs operator `.=` – `this.sum()` has to be used in those cases as well.
|
||||
|
||||
#### Formatting Decimal Numbers To Precision
|
||||
|
||||
The `.toFixed ()` method has [known rounding bugs](https://www.google.com/search?q=toFixed+bug) in JavaScript, and so do the other rounding methods in the other languages as well. In order to work with number formatting consistently, we need to use the [`decimalToPrecision` method as described in the Manual](https://github.com/ccxt/ccxt/wiki/Manual#methods-for-formatting-decimals).
|
||||
|
||||
#### Escaped Control Characters
|
||||
|
||||
When using strings containing control characters like `"\n"`, `"\t"`, always enclose them in double quotes (`"`), not single quotes (`'`)! Single-quoted strings are not parsed for control characters and are treated as is in many languages apart from JavaScript. Therefore for tabs and newlines to work in PHP, we need to surround them with double quotes (especially in the `sign()` implementation).
|
||||
|
||||
Bad:
|
||||
|
||||
```JavaScript
|
||||
const a = 'GET' + method.toLowerCase () + '\n' + path;
|
||||
const b = 'api\nfoobar.com\n';
|
||||
```
|
||||
|
||||
Good:
|
||||
|
||||
```JavaScript
|
||||
const a = 'GET' + method.toLowerCase () + "\n" + path; // eslint-disable-line quotes
|
||||
// eslint-disable-next-line quotes
|
||||
const b = "api\nfoobar.com\n";
|
||||
```
|
||||
|
||||
**↑ The `eslint-*` comments are mandatory!**
|
||||
|
||||
#### Using Ternary Conditionals
|
||||
|
||||
Do not use heavy ternary (`?:`) conditionals, **always use brackets in ternary operators!**
|
||||
|
||||
Despite that there is operator precedence in the programming languages themselves, the transpiler is regex-based and it does no code introspection, therefore it treats everything as plaintext.
|
||||
|
||||
The brackets are needed to hint the transpiler which part of the conditional is which. In the absence of brackets it's hard to understand the line and the intent of the developer.
|
||||
|
||||
Here are some examples of a badly-designed code that will break the transpiler:
|
||||
|
||||
```JavaScript
|
||||
// this is an example of bad codestyle that will likely break the transpiler
|
||||
const foo = {
|
||||
'bar': 'a' + qux === 'baz' ? this.a () : this.b () + 'b',
|
||||
};
|
||||
```
|
||||
|
||||
```JavaScript
|
||||
// this confuses the transpiler and a human developer as well
|
||||
const foo = 'bar' + baz + qux ? 'a' : '' + this.c ();
|
||||
```
|
||||
|
||||
Adding surrounding brackets to corresponding parts would be a more or less correct way to resolve it.
|
||||
|
||||
```JavaScript
|
||||
const foo = {
|
||||
'bar': (qux === 'baz') ? this.a () : this.b (), // much better now
|
||||
};
|
||||
```
|
||||
|
||||
The universally-working way to solve it is to just break the complex line into a few simpler lines, even at a cost of adding extra lines and conditionals:
|
||||
|
||||
```JavaScript
|
||||
// before:
|
||||
// const foo = {
|
||||
// 'bar': 'a' + qux === 'baz' ? this.a () : this.b () + 'b',
|
||||
// };
|
||||
// ----------------------------------------------------------------------------
|
||||
// after:
|
||||
const bar = (qux === 'baz') ? this.a () : this.b ();
|
||||
const foo = {
|
||||
'bar': 'a' + bar + 'b',
|
||||
};
|
||||
```
|
||||
|
||||
Or even:
|
||||
|
||||
```JavaScript
|
||||
// before:
|
||||
// const foo = 'bar' + baz + qux ? 'a' : '' + this.c ();
|
||||
// ----------------------------------------------------------------------------
|
||||
// after:
|
||||
let foo = 'bar' + baz;
|
||||
if (qux) {
|
||||
foo += 'a';
|
||||
};
|
||||
foo += this.c ();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### New Exchange Integrations
|
||||
|
||||
**REMEMBER:** The key reason why this library is used at all is **Unification**. When developing a new exchange file the goal is not to implement it somehow, but to implement it in a very pedantic, precise and exact way, just as the other exchanges are implemented. For that we have to copy bits of logic from other exchanges and make sure that the new exchange conforms to the Manual in the following aspects:
|
||||
|
||||
- market ids, trading pair symbols, currency ids, token codes, symbolic unification and `commonCurrencies` must be standardized in all parsing methods (`fetchMarkets`, `fetchCurrencies`, `parseTrade`, `parseOrder`, ...)
|
||||
- all unified API method names and arguments are standard – can't add or change them freely
|
||||
- all parser input must be `safe`-sanitized as [described above](#sanitizing-input-with-safe-methods)
|
||||
- for bulk operations the base methods should be used (`parseTrades`, `parseOrders`, note the `s` plural ending)
|
||||
- use as much of base functionality as you can, do not reinvent the wheel, nor the bicycle, nor the bicycle wheel
|
||||
- respect default argument values in `fetch`-methods, check if `since` and `limit` are `undefined` and do not send them to the exchange, we intentionally use the exchanges' defaults in such cases
|
||||
- when implementing a unified method that has some arguments – we can't ignore or miss any of those arguments
|
||||
- all structures returned from the unified methods must conform to their specifications from the Manual
|
||||
- all API endpoints have to be listed out with proper support for params substituted in the URLs
|
||||
|
||||
Please, see the following document for new integrations: https://github.com/ccxt/ccxt/wiki/Requirements
|
||||
|
||||
A quick merge of a Pull Request for a new exchange integration depends on consistency and compliance with the above unified rules and standards. Breaking one of those is the key reason for not merging a Pull Request.
|
||||
|
||||
**If you want to add (support for) another exchange, or implement a new method for a particular exchange, then the best way to make it a consistent improvement is to learn from example. Take a look at how same things are implemented in other exchanges (we recommend certified exchanges) and try to copy the code flow and style.**
|
||||
|
||||
The basic JSON-skeleton for a new exchange integration is as follows:
|
||||
|
||||
```
|
||||
{
|
||||
'id': 'example',
|
||||
'name': 'Example Exchange',
|
||||
'country': [ 'US', 'EU', 'CN', 'RU' ],
|
||||
'rateLimit': 1000,
|
||||
'version': '1',
|
||||
'comment': 'This comment is optional',
|
||||
'urls': {
|
||||
'logo': 'https://example.com/image.jpg',
|
||||
'api': 'https://api.example.com/api',
|
||||
'www': 'https://www.example.com',
|
||||
'doc': [
|
||||
'https://www.example.com/docs/api',
|
||||
'https://www.example.com/docs/howto',
|
||||
'https://github.com/example/docs',
|
||||
],
|
||||
},
|
||||
'api': {
|
||||
'public': {
|
||||
'get': [
|
||||
'endpoint/example',
|
||||
'orderbook/{pair}/full',
|
||||
'{pair}/ticker',
|
||||
],
|
||||
},
|
||||
'private': {
|
||||
'post': [
|
||||
'balance',
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Implicit API Methods
|
||||
|
||||
In the code for each exchange, you'll notice that the functions that make API requests aren't explicitly defined. This is because the `api` definition in the exchange description JSON is used to create *magic functions* (aka *partial functions* or *closures*) inside the exchange subclass. That implicit injection is done by the `defineRestApi/define_rest_api` base exchange method.
|
||||
|
||||
Each partial function takes a dictionary of `params` and returns the API response. In the example JSON above, the `'endpoint/example'` results in the injection of a `this.publicGetEndpointExample` function. Similarly, the `'orderbook/{pair}/full'` results in a `this.publicGetOrderbookPairFull` function, that takes a ``pair`` parameter (again, passed in the `params` argument).
|
||||
|
||||
Upon instantiation the base exchange class takes each URL from its list of endpoints, splits it into words, and then makes up a callable function name from those words by using a partial construct. That process is the same in JS, Python and PHP as well. It is also described here:
|
||||
|
||||
- https://github.com/ccxt/ccxt/wiki/Manual#api-methods--endpoints
|
||||
- https://github.com/ccxt/ccxt/wiki/Manual#implicit-api-methods
|
||||
- https://github.com/ccxt-dev/ccxt/wiki/Manual#api-method-naming-conventions
|
||||
|
||||
```UNDER CONSTRUCTION```
|
||||
|
||||
### Continuous Integration
|
||||
|
||||
Builds are automated with [Travis CI](https://travis-ci.org/ccxt/ccxt). The build steps for Travis CI are described in the [`.travis.yml`](https://github.com/ccxt/ccxt/blob/master/.travis.yml) file.
|
||||
|
||||
Windows builds are automated with [Appveyor](https://ci.appveyor.com/project/ccxt/ccxt). The build steps for Appveyor are in the [`appveyor.yml`](https://github.com/ccxt/ccxt/blob/master/appveyor.yml) file.
|
||||
|
||||
Incoming pull requests are automatically validated by the CI service. You can watch the build process online here: [travis-ci.org/ccxt/ccxt/builds](https://travis-ci.org/ccxt/ccxt/builds).
|
||||
|
||||
### How To Build & Run Tests On Your Local Machine
|
||||
|
||||
Before building for the first time, install Node dependencies (skip this step if you're running our Docker image):
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
The command below will build everything and generate PHP/Python versions from source JS files:
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
The following command will test the built generated files (for all exchanges, symbols and languages):
|
||||
|
||||
```
|
||||
node run-tests
|
||||
```
|
||||
|
||||
You can restrict tests to a specific language, a particular exchange or symbol:
|
||||
|
||||
```
|
||||
node run-tests [--php] [--js] [--python] [--python3] [exchange] [symbol]
|
||||
```
|
||||
|
||||
For example, the first of the following lines will only test the source JS version of the library (`ccxt.js`). It does not require an `npm run build` before running it (can be useful if you need to verify quickly whether your changes break the code or not):
|
||||
|
||||
```shell
|
||||
|
||||
node run-tests --js # test master ccxt.js, all exchanges
|
||||
|
||||
# other examples require the 'npm run build' to run
|
||||
|
||||
node run-tests --python # test Python 2 version, all exchanges
|
||||
node run-tests --php bitfinex # test Bitfinex with PHP
|
||||
node run-tests --python3 kraken # test Kraken with Python 3, requires 'npm run build'
|
||||
```
|
||||
|
||||
## Committing Changes To The Repository
|
||||
|
||||
The build process generates many changes in the transpiled exchange files, e.g. for Python and PHP. **You should NOT commit them to GitHub, commit only the base (JS) file changes please**.
|
||||
|
||||
You can hide the changes in the generated files by running this command (after that, the generated files are no longer marked as changed):
|
||||
|
||||
```
|
||||
npm run git-ignore-generated-files
|
||||
```
|
||||
|
||||
Previously we had that command implemented as a final build step, but it caused problems with subsequent `git pull` and also branch selection commands (when a conflict occurred in those files that have been marked as ignored). So if you experience an issue with that, you can un-ignore those files by executing:
|
||||
|
||||
```
|
||||
npm run git-unignore-generated-files
|
||||
```
|
||||
|
||||
## Financial Contributions
|
||||
|
||||
We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/ccxt).
|
||||
Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
|
||||
|
||||
```
|
||||
ETH 0x26a3CB49578F07000575405a57888681249c35Fd (ETH only!)
|
||||
BTC 33RmVRfhK2WZVQR1R83h2e9yXoqRNDvJva
|
||||
BCH 1GN9p233TvNcNQFthCgfiHUnj5JRKEc2Ze
|
||||
LTC LbT8mkAqQBphc4yxLXEDgYDfEax74et3bP
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
Thank you to all the people who have already contributed to ccxt!
|
||||
|
||||
<a href="graphs/contributors"><img src="https://opencollective.com/ccxt/contributors.svg?width=890" /></a>
|
||||
|
||||
### Backers
|
||||
|
||||
Thank you to all our backers! [[Become a backer](https://opencollective.com/ccxt#backer)]
|
||||
|
||||
<a href="https://opencollective.com/ccxt#backers" target="_blank"><img src="https://opencollective.com/ccxt/backers.svg?width=890"></a>
|
||||
|
||||
### Supporters
|
||||
|
||||
Support this project by becoming a supporter. Your avatar will show up here with a link to your website.
|
||||
|
||||
[[Become a supporter](https://opencollective.com/ccxt#supporter)]
|
||||
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/0/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/1/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/2/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/3/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/4/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/5/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/6/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/7/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/8/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/9/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/9/avatar.svg"></a>
|
||||
|
||||
### Sponsors
|
||||
|
||||
Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/ccxt#sponsor))
|
||||
|
||||
[[Become a sponsor](https://opencollective.com/ccxt#sponsor)]
|
||||
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/9/avatar.svg"></a>
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright © 2017 Igor Kroitor
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,551 @@
|
||||
# CCXT – CryptoCurrency eXchange Trading Library
|
||||
|
||||
[](https://travis-ci.com/ccxt/ccxt) [](https://npmjs.com/package/ccxt) [](https://pypi.python.org/pypi/ccxt) [](https://www.npmjs.com/package/ccxt) [](https://discord.gg/dhzSKYU) [](https://github.com/ccxt/ccxt/wiki/Exchange-Markets) [](https://opencollective.com/ccxt)
|
||||
[](https://twitter.com/ccxt_official)
|
||||
|
||||
A JavaScript / Python / PHP library for cryptocurrency trading and e-commerce with support for many bitcoin/ether/altcoin exchange markets and merchant APIs.
|
||||
|
||||
### [Install](#install) · [Usage](#usage) · [Manual](https://github.com/ccxt/ccxt/wiki) · [FAQ](https://github.com/ccxt/ccxt/wiki/FAQ) · [Examples](https://github.com/ccxt/ccxt/tree/master/examples) · [Contributing](https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md) · [Social](#social)
|
||||
|
||||
The **CCXT** library is used to connect and trade with cryptocurrency exchanges and payment processing services worldwide. It provides quick access to market data for storage, analysis, visualization, indicator development, algorithmic trading, strategy backtesting, bot programming, and related software engineering.
|
||||
|
||||
It is intended to be used by **coders, developers, technically-skilled traders, data-scientists and financial analysts** for building trading algorithms.
|
||||
|
||||
Current feature list:
|
||||
|
||||
- support for many cryptocurrency exchanges — more coming soon
|
||||
- fully implemented public and private APIs
|
||||
- optional normalized data for cross-exchange analytics and arbitrage
|
||||
- an out of the box unified API that is extremely easy to integrate
|
||||
- works in Node 7.6+, Python 3, PHP 5.4+, and web browsers
|
||||
|
||||
## Sponsored Promotion
|
||||
|
||||
[](https://ccxt.pro) **[A JavaScript / Python / PHP cryptocurrency exchange trading WebSocket API for professionals](https://ccxt.pro)**
|
||||
|
||||
## See Also
|
||||
|
||||
- <sub>[](https://quadency.com?utm_source=ccxt)</sub> **[Quadency](https://quadency.com?utm_source=ccxt)** — trading automation terminal for leading exchanges with streaming APIs + Python IDE.
|
||||
- <sub>[](https://tab-trader.com/?utm_source=ccxt)</sub> **[TabTrader](https://tab-trader.com/?utm_source=ccxt)** — trading on all exchanges in one app. Avaliable on [Android](https://play.google.com/store/apps/details?id=com.tabtrader.android&referrer=utm_source%3Dccxt) and [iOS](https://itunes.apple.com/app/apple-store/id1095716562?mt=8).
|
||||
|
||||
|
||||
## Certified Cryptocurrency Exchanges
|
||||
|
||||
|
||||
| logo | id | name | ver | doc | certified | pro |
|
||||
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|-----------------------------------------------------------------------------|:---:|:----------------------------------------------------------------------------------:|-----------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|
|
||||
| [](https://www.binance.com/?ref=10205187) | binance | [Binance](https://www.binance.com/?ref=10205187) | * | [API](https://binance-docs.github.io/apidocs/spot/en) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://www.bitfinex.com/?refcode=P61eYxFL) | bitfinex | [Bitfinex](https://www.bitfinex.com/?refcode=P61eYxFL) | 1 | [API](https://docs.bitfinex.com/v1/docs) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B) | bittrex | [Bittrex](https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B) | 3 | [API](https://bittrex.github.io/api/v3) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://bitvavo.com/?a=24F34952F7) | bitvavo | [Bitvavo](https://bitvavo.com/?a=24F34952F7) | 2 | [API](https://docs.bitvavo.com/) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://www.byte-trade.com) | bytetrade | [ByteTrade](https://www.byte-trade.com) | * | [API](https://docs.byte-trade.com/#description) | [](https://github.com/ccxt/ccxt/wiki/Certification) | |
|
||||
| [](https://currency.com/trading/signup?c=362jaimv&pid=referral) | currencycom | [Currency.com](https://currency.com/trading/signup?c=362jaimv&pid=referral) | 1 | [API](https://currency.com/api) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://eterbase.exchange/invite/1wjjh4Pe) | eterbase | [Eterbase](https://eterbase.exchange/invite/1wjjh4Pe) | 1 | [API](https://developers.eterbase.exchange) | [](https://github.com/ccxt/ccxt/wiki/Certification) | |
|
||||
| [](https://ftx.com/#a=1623029) | ftx | [FTX](https://ftx.com/#a=1623029) | * | [API](https://github.com/ftexchange/ftx) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://idex.io) | idex | [IDEX](https://idex.io) | 2 | [API](https://docs.idex.io/) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://www.kraken.com) | kraken | [Kraken](https://www.kraken.com) | 0 | [API](https://www.kraken.com/features/api) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://upbit.com) | upbit | [Upbit](https://upbit.com) | 1 | [API](https://docs.upbit.com/docs/%EC%9A%94%EC%B2%AD-%EC%88%98-%EC%A0%9C%ED%95%9C) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://waves.exchange) | wavesexchange | [Waves.Exchange](https://waves.exchange) | * | [API](https://docs.waves.exchange) | [](https://github.com/ccxt/ccxt/wiki/Certification) | |
|
||||
| [](https://xena.exchange) | xena | [Xena Exchange](https://xena.exchange) | * | [API](https://support.xena.exchange/support/solutions/44000808700) | [](https://github.com/ccxt/ccxt/wiki/Certification) | |
|
||||
|
||||
## Supported Cryptocurrency Exchange Markets
|
||||
|
||||
The CCXT library currently supports the following 123 cryptocurrency exchange markets and trading APIs:
|
||||
|
||||
| logo | id | name | ver | doc | certified | pro |
|
||||
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------|-----------------------------------------------------------------------------------------|:---:|:-------------------------------------------------------------------------------------------:|-----------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|
|
||||
| [](https://acx.io) | acx | [ACX](https://acx.io) | 2 | [API](https://acx.io/documents/api_v2) | | |
|
||||
| [](https://aofex.com/#/register?key=9763840) | aofex | [AOFEX](https://aofex.com/#/register?key=9763840) | * | [API](https://aofex.zendesk.com/hc/en-us/sections/360005576574-API) | | |
|
||||
| [](https://www.bcex.top/register?invite_code=758978&lang=en) | bcex | [BCEX](https://www.bcex.top/register?invite_code=758978&lang=en) | 1 | [API](https://github.com/BCEX-TECHNOLOGY-LIMITED/API_Docs/wiki/Interface) | | |
|
||||
| [](https://bequant.io) | bequant | [Bequant](https://bequant.io) | 2 | [API](https://api.bequant.io/) | | [](https://ccxt.pro) |
|
||||
| [](https://w2.bibox365.com/login/register?invite_code=05Kj3I) | bibox | [Bibox](https://w2.bibox365.com/login/register?invite_code=05Kj3I) | 1 | [API](https://biboxcom.github.io/en/) | | |
|
||||
| [](https://b1.run/users/new?code=D3LLBVFT) | bigone | [BigONE](https://b1.run/users/new?code=D3LLBVFT) | 3 | [API](https://open.big.one/docs/api.html) | | |
|
||||
| [](https://www.binance.com/?ref=10205187) | binance | [Binance](https://www.binance.com/?ref=10205187) | * | [API](https://binance-docs.github.io/apidocs/spot/en) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://www.binance.us/?ref=35005074) | binanceus | [Binance US](https://www.binance.us/?ref=35005074) | * | [API](https://github.com/binance-us/binance-official-api-docs) | | [](https://ccxt.pro) |
|
||||
| [](https://bit2c.co.il/Aff/63bfed10-e359-420c-ab5a-ad368dab0baf) | bit2c | [Bit2C](https://bit2c.co.il/Aff/63bfed10-e359-420c-ab5a-ad368dab0baf) | * | [API](https://www.bit2c.co.il/home/api) | | |
|
||||
| [](https://bitbank.cc/) | bitbank | [bitbank](https://bitbank.cc/) | 1 | [API](https://docs.bitbank.cc/) | | |
|
||||
| [](https://auth.bitbay.net/ref/jHlbB4mIkdS1) | bitbay | [BitBay](https://auth.bitbay.net/ref/jHlbB4mIkdS1) | * | [API](https://bitbay.net/public-api) | | |
|
||||
| [](https://exchange.bitcoin.com/referral/da948b21d6c92d69) | bitcoincom | [bitcoin.com](https://exchange.bitcoin.com/referral/da948b21d6c92d69) | 2 | [API](https://api.exchange.bitcoin.com/api/2/explore) | | [](https://ccxt.pro) |
|
||||
| [](https://www.bitfinex.com/?refcode=P61eYxFL) | bitfinex | [Bitfinex](https://www.bitfinex.com/?refcode=P61eYxFL) | 1 | [API](https://docs.bitfinex.com/v1/docs) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://www.bitfinex.com/?refcode=P61eYxFL) | bitfinex2 | [Bitfinex](https://www.bitfinex.com/?refcode=P61eYxFL) | 2 | [API](https://docs.bitfinex.com/v2/docs/) | | |
|
||||
| [](https://bitflyer.com) | bitflyer | [bitFlyer](https://bitflyer.com) | 1 | [API](https://lightning.bitflyer.com/docs?lang=en) | | |
|
||||
| [](https://www.bitforex.com/en/invitationRegister?inviterId=1867438) | bitforex | [Bitforex](https://www.bitforex.com/en/invitationRegister?inviterId=1867438) | 1 | [API](https://github.com/githubdev2020/API_Doc_en/wiki) | | |
|
||||
| [](https://www.bitget.com/expressly?languageType=0&channelCode=ccxt&vipCode=tg9j) | bitget | [Bitget](https://www.bitget.com/expressly?languageType=0&channelCode=ccxt&vipCode=tg9j) | 3 | [API](https://bitgetlimited.github.io/apidoc/en/swap) | | |
|
||||
| [](https://www.bithumb.com) | bithumb | [Bithumb](https://www.bithumb.com) | * | [API](https://apidocs.bithumb.com) | | |
|
||||
| [](https://www.bitkk.com) | bitkk | [bitkk](https://www.bitkk.com) | 1 | [API](https://www.bitkk.com/i/developer) | | |
|
||||
| [](http://www.bitmart.com/?r=rQCFLh) | bitmart | [BitMart](http://www.bitmart.com/?r=rQCFLh) | 1 | [API](https://github.com/bitmartexchange/bitmart-official-api-docs) | | |
|
||||
| [](https://bitmax.io/#/register?inviteCode=EL6BXBQM) | bitmax | [BitMax](https://bitmax.io/#/register?inviteCode=EL6BXBQM) | 1 | [API](https://bitmax-exchange.github.io/bitmax-pro-api/#bitmax-pro-api-documentation) | | |
|
||||
| [](https://www.bitmex.com/register/upZpOX) | bitmex | [BitMEX](https://www.bitmex.com/register/upZpOX) | 1 | [API](https://www.bitmex.com/app/apiOverview) | | [](https://ccxt.pro) |
|
||||
| [](https://www.bitpanda.com/en/pro) | bitpanda | [Bitpanda Pro](https://www.bitpanda.com/en/pro) | 1 | [API](https://developers.bitpanda.com/exchange/) | | |
|
||||
| [](https://bitso.com/?ref=itej) | bitso | [Bitso](https://bitso.com/?ref=itej) | 3 | [API](https://bitso.com/api_info) | | |
|
||||
| [](https://www.bitstamp.net) | bitstamp | [Bitstamp](https://www.bitstamp.net) | 2 | [API](https://www.bitstamp.net/api) | | [](https://ccxt.pro) |
|
||||
| [](https://www.bitstamp.net) | bitstamp1 | [Bitstamp](https://www.bitstamp.net) | 1 | [API](https://www.bitstamp.net/api) | | |
|
||||
| [](https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B) | bittrex | [Bittrex](https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B) | 3 | [API](https://bittrex.github.io/api/v3) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://bitvavo.com/?a=24F34952F7) | bitvavo | [Bitvavo](https://bitvavo.com/?a=24F34952F7) | 2 | [API](https://docs.bitvavo.com/) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://u.bitz.com/register?invite_code=1429193) | bitz | [Bit-Z](https://u.bitz.com/register?invite_code=1429193) | 2 | [API](https://apidoc.bitz.com/en/) | | |
|
||||
| [](https://bl3p.eu) | bl3p | [BL3P](https://bl3p.eu) | 1 | [API](https://github.com/BitonicNL/bl3p-api/tree/master/docs) | | |
|
||||
| [](https://bleutrade.com) | bleutrade | [Bleutrade](https://bleutrade.com) | * | [API](https://app.swaggerhub.com/apis-docs/bleu/white-label/3.0.0) | | |
|
||||
| [](https://braziliex.com/?ref=5FE61AB6F6D67DA885BC98BA27223465) | braziliex | [Braziliex](https://braziliex.com/?ref=5FE61AB6F6D67DA885BC98BA27223465) | * | [API](https://braziliex.com/exchange/api.php) | | |
|
||||
| [](https://btc-alpha.com/?r=123788) | btcalpha | [BTC-Alpha](https://btc-alpha.com/?r=123788) | 1 | [API](https://btc-alpha.github.io/api-docs) | | |
|
||||
| [](https://www.btcbox.co.jp/) | btcbox | [BtcBox](https://www.btcbox.co.jp/) | 1 | [API](https://blog.btcbox.jp/en/archives/8762) | | |
|
||||
| [](https://btcmarkets.net) | btcmarkets | [BTC Markets](https://btcmarkets.net) | 3 | [API](https://api.btcmarkets.net/doc/v3) | | |
|
||||
| [](https://btc-trade.com.ua/registration/22689) | btctradeua | [BTC Trade UA](https://btc-trade.com.ua/registration/22689) | * | [API](https://docs.google.com/document/d/1ocYA0yMy_RXd561sfG3qEPZ80kyll36HUxvCRe5GbhE/edit) | | |
|
||||
| [](https://www.btcturk.com) | btcturk | [BTCTurk](https://www.btcturk.com) | * | [API](https://github.com/BTCTrader/broker-api-docs) | | |
|
||||
| [](https://www.buda.com) | buda | [Buda](https://www.buda.com) | 2 | [API](https://api.buda.com) | | |
|
||||
| [](https://www.bw.com/regGetCommission/N3JuT1R3bWxKTE0) | bw | [BW](https://www.bw.com/regGetCommission/N3JuT1R3bWxKTE0) | 1 | [API](https://github.com/bw-exchange/api_docs_en/wiki) | | |
|
||||
| [](https://www.bybit.com/app/register?ref=X7Prm) | bybit | [Bybit](https://www.bybit.com/app/register?ref=X7Prm) | 2 | [API](https://bybit-exchange.github.io/docs/inverse/) | | |
|
||||
| [](https://www.byte-trade.com) | bytetrade | [ByteTrade](https://www.byte-trade.com) | * | [API](https://docs.byte-trade.com/#description) | [](https://github.com/ccxt/ccxt/wiki/Certification) | |
|
||||
| [](https://cex.io/r/0/up105393824/0/) | cex | [CEX.IO](https://cex.io/r/0/up105393824/0/) | * | [API](https://cex.io/cex-api) | | |
|
||||
| [](https://chilebit.net) | chilebit | [ChileBit](https://chilebit.net) | 1 | [API](https://blinktrade.com/docs) | | |
|
||||
| [](https://www.coinbase.com/join/58cbe25a355148797479dbd2) | coinbase | [Coinbase](https://www.coinbase.com/join/58cbe25a355148797479dbd2) | 2 | [API](https://developers.coinbase.com/api/v2) | | |
|
||||
| [](https://prime.coinbase.com) | coinbaseprime | [Coinbase Prime](https://prime.coinbase.com) | * | [API](https://docs.prime.coinbase.com) | | [](https://ccxt.pro) |
|
||||
| [](https://pro.coinbase.com/) | coinbasepro | [Coinbase Pro](https://pro.coinbase.com/) | * | [API](https://docs.pro.coinbase.com) | | [](https://ccxt.pro) |
|
||||
| [](https://coincheck.com) | coincheck | [coincheck](https://coincheck.com) | * | [API](https://coincheck.com/documents/exchange/api) | | |
|
||||
| [](https://www.coinegg.com/user/register?invite=523218) | coinegg | [CoinEgg](https://www.coinegg.com/user/register?invite=523218) | * | [API](https://www.coinegg.com/explain.api.html) | | |
|
||||
| [](https://www.coinex.com/register?refer_code=yw5fz) | coinex | [CoinEx](https://www.coinex.com/register?refer_code=yw5fz) | 1 | [API](https://github.com/coinexcom/coinex_exchange_api/wiki) | | |
|
||||
| [](https://coinfalcon.com/?ref=CFJSVGTUPASB) | coinfalcon | [CoinFalcon](https://coinfalcon.com/?ref=CFJSVGTUPASB) | 1 | [API](https://docs.coinfalcon.com) | | |
|
||||
| [](https://www.coinfloor.co.uk) | coinfloor | [coinfloor](https://www.coinfloor.co.uk) | * | [API](https://github.com/coinfloor/api) | | |
|
||||
| [](https://www.coingi.com/?r=XTPPMC) | coingi | [Coingi](https://www.coingi.com/?r=XTPPMC) | * | [API](https://coingi.docs.apiary.io) | | |
|
||||
| [](https://coinmarketcap.com) | coinmarketcap | [CoinMarketCap](https://coinmarketcap.com) | 1 | [API](https://coinmarketcap.com/api) | | |
|
||||
| [](https://coinmate.io?referral=YTFkM1RsOWFObVpmY1ZjMGREQmpTRnBsWjJJNVp3PT0) | coinmate | [CoinMate](https://coinmate.io?referral=YTFkM1RsOWFObVpmY1ZjMGREQmpTRnBsWjJJNVp3PT0) | * | [API](https://coinmate.docs.apiary.io) | | |
|
||||
| [](https://coinone.co.kr) | coinone | [CoinOne](https://coinone.co.kr) | 2 | [API](https://doc.coinone.co.kr) | | |
|
||||
| [](https://www.coinspot.com.au/register?code=PJURCU) | coinspot | [CoinSpot](https://www.coinspot.com.au/register?code=PJURCU) | * | [API](https://www.coinspot.com.au/api) | | |
|
||||
| [](https://crex24.com/?refid=slxsjsjtil8xexl9hksr) | crex24 | [CREX24](https://crex24.com/?refid=slxsjsjtil8xexl9hksr) | 2 | [API](https://docs.crex24.com/trade-api/v2) | | |
|
||||
| [](https://currency.com/trading/signup?c=362jaimv&pid=referral) | currencycom | [Currency.com](https://currency.com/trading/signup?c=362jaimv&pid=referral) | 1 | [API](https://currency.com/api) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://www.deribit.com/reg-1189.4038) | deribit | [Deribit](https://www.deribit.com/reg-1189.4038) | 2 | [API](https://docs.deribit.com/v2) | | |
|
||||
| [](https://www.digifinex.com/en-ww/from/DhOzBg?channelCode=ljaUPp) | digifinex | [DigiFinex](https://www.digifinex.com/en-ww/from/DhOzBg?channelCode=ljaUPp) | 3 | [API](https://docs.digifinex.com) | | |
|
||||
| [](https://dsxglobal.com) | dsx | [DSX](https://dsxglobal.com) | 3 | [API](https://dsxglobal.com/developers/publicApi) | | |
|
||||
| [](https://eterbase.exchange/invite/1wjjh4Pe) | eterbase | [Eterbase](https://eterbase.exchange/invite/1wjjh4Pe) | 1 | [API](https://developers.eterbase.exchange) | [](https://github.com/ccxt/ccxt/wiki/Certification) | |
|
||||
| [](https://exmo.me/?ref=131685) | exmo | [EXMO](https://exmo.me/?ref=131685) | 1.1 | [API](https://exmo.me/en/api_doc?ref=131685) | | |
|
||||
| [](https://www.exx.com/r/fde4260159e53ab8a58cc9186d35501f?recommQd=1) | exx | [EXX](https://www.exx.com/r/fde4260159e53ab8a58cc9186d35501f?recommQd=1) | * | [API](https://www.exx.com/help/restApi) | | |
|
||||
| [](https://www.fcoin.com/i/Z5P7V) | fcoin | [FCoin](https://www.fcoin.com/i/Z5P7V) | 2 | [API](https://developer.fcoin.com) | | |
|
||||
| [](https://www.fcoinjp.com) | fcoinjp | [FCoinJP](https://www.fcoinjp.com) | 2 | [API](https://developer.fcoin.com) | | |
|
||||
| [](https://www.flowbtc.com.br) | flowbtc | [flowBTC](https://www.flowbtc.com.br) | 1 | [API](https://www.flowbtc.com.br/api.html) | | |
|
||||
| [](https://foxbit.com.br/exchange) | foxbit | [FoxBit](https://foxbit.com.br/exchange) | 1 | [API](https://foxbit.com.br/api/) | | |
|
||||
| [](https://ftx.com/#a=1623029) | ftx | [FTX](https://ftx.com/#a=1623029) | * | [API](https://github.com/ftexchange/ftx) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://www.gate.io/signup/2436035) | gateio | [Gate.io](https://www.gate.io/signup/2436035) | 2 | [API](https://gate.io/api2) | | [](https://ccxt.pro) |
|
||||
| [](https://gemini.com/) | gemini | [Gemini](https://gemini.com/) | 1 | [API](https://docs.gemini.com/rest-api) | | |
|
||||
| [](https://www.hbtc.com/register/O2S8NS) | hbtc | [HBTC](https://www.hbtc.com/register/O2S8NS) | 1 | [API](https://github.com/bhexopen/BHEX-OpenApi/tree/master/doc) | | |
|
||||
| [](https://hitbtc.com/?ref_id=5a5d39a65d466) | hitbtc | [HitBTC](https://hitbtc.com/?ref_id=5a5d39a65d466) | 2 | [API](https://api.hitbtc.com) | | [](https://ccxt.pro) |
|
||||
| [](https://pro.hollaex.com/signup?affiliation_code=QSWA6G) | hollaex | [HollaEx](https://pro.hollaex.com/signup?affiliation_code=QSWA6G) | 1 | [API](https://apidocs.hollaex.com) | | |
|
||||
| [](https://www.huobi.co.jp/register/?invite_code=znnq3) | huobijp | [Huobi Japan](https://www.huobi.co.jp/register/?invite_code=znnq3) | 1 | [API](https://api-doc.huobi.co.jp) | | [](https://ccxt.pro) |
|
||||
| [](https://www.huobi.com/en-us/topic/invited/?invite_code=rwrd3) | huobipro | [Huobi Pro](https://www.huobi.com/en-us/topic/invited/?invite_code=rwrd3) | 1 | [API](https://huobiapi.github.io/docs/spot/v1/cn/) | | [](https://ccxt.pro) |
|
||||
| [](https://www.huobi.com.ru/invite?invite_code=esc74) | huobiru | [Huobi Russia](https://www.huobi.com.ru/invite?invite_code=esc74) | 1 | [API](https://github.com/cloudapidoc/API_Docs_en) | | [](https://ccxt.pro) |
|
||||
| [](https://ice3x.com?ref=14341802) | ice3x | [ICE3X](https://ice3x.com?ref=14341802) | 1 | [API](https://ice3x.co.za/ice-cubed-bitcoin-exchange-api-documentation-1-june-2017) | | |
|
||||
| [](https://idex.io) | idex | [IDEX](https://idex.io) | 2 | [API](https://docs.idex.io/) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://www.independentreserve.com) | independentreserve | [Independent Reserve](https://www.independentreserve.com) | * | [API](https://www.independentreserve.com/API) | | |
|
||||
| [](https://indodax.com/ref/testbitcoincoid/1) | indodax | [INDODAX](https://indodax.com/ref/testbitcoincoid/1) | 2.0 | [API](https://github.com/btcid/indodax-official-api-docs) | | |
|
||||
| [](https://www.itbit.com) | itbit | [itBit](https://www.itbit.com) | 1 | [API](https://api.itbit.com/docs) | | |
|
||||
| [](https://www.kraken.com) | kraken | [Kraken](https://www.kraken.com) | 0 | [API](https://www.kraken.com/features/api) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://www.kucoin.com/?rcode=E5wkqe) | kucoin | [KuCoin](https://www.kucoin.com/?rcode=E5wkqe) | 2 | [API](https://docs.kucoin.com) | | [](https://ccxt.pro) |
|
||||
| [](https://kuna.io?r=kunaid-gvfihe8az7o4) | kuna | [Kuna](https://kuna.io?r=kunaid-gvfihe8az7o4) | 2 | [API](https://kuna.io/documents/api) | | |
|
||||
| [](https://www.lakebtc.com) | lakebtc | [LakeBTC](https://www.lakebtc.com) | 2 | [API](https://www.lakebtc.com/s/api_v2) | | |
|
||||
| [](https://latoken.com) | latoken | [Latoken](https://latoken.com) | 1 | [API](https://api.latoken.com) | | |
|
||||
| [](https://www.lbex.io/invite?icode=7QCY) | lbank | [LBank](https://www.lbex.io/invite?icode=7QCY) | 1 | [API](https://github.com/LBank-exchange/lbank-official-api-docs) | | |
|
||||
| [](https://www.liquid.com/sign-up/?affiliate=SbzC62lt30976) | liquid | [Liquid](https://www.liquid.com/sign-up/?affiliate=SbzC62lt30976) | 2 | [API](https://developers.liquid.com) | | |
|
||||
| [](https://livecoin.net/?from=Livecoin-CQ1hfx44) | livecoin | [LiveCoin](https://livecoin.net/?from=Livecoin-CQ1hfx44) | * | [API](https://www.livecoin.net/api?lang=en) | | |
|
||||
| [](https://www.luno.com/invite/44893A) | luno | [luno](https://www.luno.com/invite/44893A) | 1 | [API](https://www.luno.com/en/api) | | |
|
||||
| [](https://www.lykke.com) | lykke | [Lykke](https://www.lykke.com) | 1 | [API](https://hft-api.lykke.com/swagger/ui/) | | |
|
||||
| [](https://www.mercadobitcoin.com.br) | mercado | [Mercado Bitcoin](https://www.mercadobitcoin.com.br) | 3 | [API](https://www.mercadobitcoin.com.br/api-doc) | | |
|
||||
| [](https://mixcoins.com) | mixcoins | [MixCoins](https://mixcoins.com) | 1 | [API](https://mixcoins.com/help/api/) | | |
|
||||
| [](https://www.novadax.com.br/?s=ccxt) | novadax | [NovaDAX](https://www.novadax.com.br/?s=ccxt) | 1 | [API](https://doc.novadax.com/pt-BR/) | | |
|
||||
| [](https://oceanex.pro/signup?referral=VE24QX) | oceanex | [OceanEx](https://oceanex.pro/signup?referral=VE24QX) | 1 | [API](https://api.oceanex.pro/doc/v1) | | |
|
||||
| [](https://www.okcoin.com/account/register?flag=activity&channelId=600001513) | okcoin | [OKCoin](https://www.okcoin.com/account/register?flag=activity&channelId=600001513) | 3 | [API](https://www.okcoin.com/docs/en/) | | [](https://ccxt.pro) |
|
||||
| [](https://www.okex.com/join/1888677) | okex | [OKEX](https://www.okex.com/join/1888677) | 3 | [API](https://www.okex.com/docs/en/) | | [](https://ccxt.pro) |
|
||||
| [](https://www.paymium.com/page/sign-up?referral=eDAzPoRQFMvaAB8sf-qj) | paymium | [Paymium](https://www.paymium.com/page/sign-up?referral=eDAzPoRQFMvaAB8sf-qj) | 1 | [API](https://github.com/Paymium/api-documentation) | | |
|
||||
| [](https://phemex.com/register?referralCode=EDNVJ) | phemex | [Phemex](https://phemex.com/register?referralCode=EDNVJ) | 1 | [API](https://github.com/phemex/phemex-api-docs) | | [](https://ccxt.pro) |
|
||||
| [](https://poloniex.com/signup?c=UBFZJRPJ) | poloniex | [Poloniex](https://poloniex.com/signup?c=UBFZJRPJ) | * | [API](https://docs.poloniex.com) | | [](https://ccxt.pro) |
|
||||
| [](https://www.probit.com/r/34608773) | probit | [ProBit](https://www.probit.com/r/34608773) | 1 | [API](https://docs-en.probit.com) | | |
|
||||
| [](https://qtrade.io/?ref=BKOQWVFGRH2C) | qtrade | [qTrade](https://qtrade.io/?ref=BKOQWVFGRH2C) | 1 | [API](https://qtrade-exchange.github.io/qtrade-docs) | | |
|
||||
| [](https://www.rightbtc.com) | rightbtc | [RightBTC](https://www.rightbtc.com) | * | [API](https://docs.rightbtc.com/api/) | | |
|
||||
| [](https://exchange.ripio.com) | ripio | [Ripio](https://exchange.ripio.com) | 1 | [API](https://exchange.ripio.com/en/api/) | | [](https://ccxt.pro) |
|
||||
| [](https://www.southxchange.com) | southxchange | [SouthXchange](https://www.southxchange.com) | * | [API](https://www.southxchange.com/Home/Api) | | |
|
||||
| [](https://app.stex.com?ref=36416021) | stex | [STEX](https://app.stex.com?ref=36416021) | 3 | [API](https://help.stex.com/en/collections/1593608-api-v3-documentation) | | |
|
||||
| [](https://surbitcoin.com) | surbitcoin | [SurBitcoin](https://surbitcoin.com) | 1 | [API](https://blinktrade.com/docs) | | |
|
||||
| [](https://therocktrading.com) | therock | [TheRockTrading](https://therocktrading.com) | 1 | [API](https://api.therocktrading.com/doc/v1/index.html) | | |
|
||||
| [](http://bit.ly/2IX0LrM) | tidebit | [TideBit](http://bit.ly/2IX0LrM) | 2 | [API](https://www.tidebit.com/documents/api/guide) | | |
|
||||
| [](https://tidex.com/exchange/?ref=57f5638d9cd7) | tidex | [Tidex](https://tidex.com/exchange/?ref=57f5638d9cd7) | 3 | [API](https://tidex.com/exchange/public-api) | | |
|
||||
| [](https://timex.io/?refcode=1x27vNkTbP1uwkCck) | timex | [TimeX](https://timex.io/?refcode=1x27vNkTbP1uwkCck) | 1 | [API](https://docs.timex.io) | | |
|
||||
| [](https://upbit.com) | upbit | [Upbit](https://upbit.com) | 1 | [API](https://docs.upbit.com/docs/%EC%9A%94%EC%B2%AD-%EC%88%98-%EC%A0%9C%ED%95%9C) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
||||
| [](https://www.vaultoro.com) | vaultoro | [Vaultoro](https://www.vaultoro.com) | 1 | [API](https://api.vaultoro.com) | | |
|
||||
| [](https://vbtc.exchange) | vbtc | [VBTC](https://vbtc.exchange) | 1 | [API](https://blinktrade.com/docs) | | |
|
||||
| [](https://vcc.exchange?ref=l4xhrH) | vcc | [VCC Exchange](https://vcc.exchange?ref=l4xhrH) | 3 | [API](https://vcc.exchange/api) | | |
|
||||
| [](https://waves.exchange) | wavesexchange | [Waves.Exchange](https://waves.exchange) | * | [API](https://docs.waves.exchange) | [](https://github.com/ccxt/ccxt/wiki/Certification) | |
|
||||
| [](https://whitebit.com/referral/d9bdf40e-28f2-4b52-b2f9-cd1415d82963) | whitebit | [WhiteBit](https://whitebit.com/referral/d9bdf40e-28f2-4b52-b2f9-cd1415d82963) | 2 | [API](https://documenter.getpostman.com/view/7473075/Szzj8dgv?version=latest) | | |
|
||||
| [](https://xbtce.com/?agent=XX97BTCXXXG687021000B) | xbtce | [xBTCe](https://xbtce.com/?agent=XX97BTCXXXG687021000B) | 1 | [API](https://www.xbtce.com/tradeapi) | | |
|
||||
| [](https://xena.exchange) | xena | [Xena Exchange](https://xena.exchange) | * | [API](https://support.xena.exchange/support/solutions/44000808700) | [](https://github.com/ccxt/ccxt/wiki/Certification) | |
|
||||
| [](https://www.yobit.net) | yobit | [YoBit](https://www.yobit.net) | 3 | [API](https://www.yobit.net/en/api/) | | |
|
||||
| [](https://zaif.jp) | zaif | [Zaif](https://zaif.jp) | 1 | [API](https://techbureau-api-document.readthedocs.io/ja/latest/index.html) | | |
|
||||
| [](https://www.zb.com) | zb | [ZB](https://www.zb.com) | 1 | [API](https://www.zb.com/i/developer) | | |
|
||||
|
||||
The list above is updated frequently, new crypto markets, exchanges, bug fixes, and API endpoints are introduced on a regular basis. See the [Manual](https://github.com/ccxt/ccxt/wiki) for more details. If you can't find a cryptocurrency exchange in the list above and want it to be added, post a link to it by opening an issue here on GitHub or send us an email.
|
||||
|
||||
The library is under [MIT license](https://github.com/ccxt/ccxt/blob/master/LICENSE.txt), that means it's absolutely free for any developer to build commercial and opensource software on top of it, but use it at your own risk with no warranties, as is.
|
||||
|
||||
---
|
||||
|
||||
## Install
|
||||
|
||||
The easiest way to install the CCXT library is to use a package manager:
|
||||
|
||||
- [ccxt in **NPM**](https://www.npmjs.com/package/ccxt) (JavaScript / Node v7.6+)
|
||||
- [ccxt in **PyPI**](https://pypi.python.org/pypi/ccxt) (Python 3.5.3+)
|
||||
- [ccxt in **Packagist/Composer**](https://packagist.org/packages/ccxt/ccxt) (PHP 5.4+)
|
||||
|
||||
This library is shipped as an all-in-one module implementation with minimalistic dependencies and requirements:
|
||||
|
||||
- [`js/`](https://github.com/ccxt/ccxt/blob/master/js/) in JavaScript
|
||||
- [`python/`](https://github.com/ccxt/ccxt/blob/master/python/) in Python (generated from JS)
|
||||
- [`php/`](https://github.com/ccxt/ccxt/blob/master/php/) in PHP (generated from JS)
|
||||
|
||||
You can also clone it into your project directory from [ccxt GitHub repository](https://github.com/ccxt/ccxt):
|
||||
|
||||
```shell
|
||||
git clone https://github.com/ccxt/ccxt.git
|
||||
```
|
||||
|
||||
### JavaScript (NPM)
|
||||
|
||||
JavaScript version of CCXT works in both Node and web browsers. Requires ES6 and `async/await` syntax support (Node 7.6.0+). When compiling with Webpack and Babel, make sure it is [not excluded](https://github.com/ccxt/ccxt/issues/225#issuecomment-331905178) in your `babel-loader` config.
|
||||
|
||||
[ccxt in **NPM**](https://www.npmjs.com/package/ccxt)
|
||||
|
||||
```shell
|
||||
npm install ccxt
|
||||
```
|
||||
|
||||
```JavaScript
|
||||
var ccxt = require ('ccxt')
|
||||
|
||||
console.log (ccxt.exchanges) // print all available exchanges
|
||||
```
|
||||
|
||||
### JavaScript (for use with the `<script>` tag):
|
||||
|
||||
All-in-one browser bundle (dependencies included), served from a CDN of your choice:
|
||||
|
||||
* jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@1.38.76/dist/ccxt.browser.js
|
||||
* unpkg: https://unpkg.com/ccxt@1.38.76/dist/ccxt.browser.js
|
||||
|
||||
CDNs are not updated in real-time and may have delays. Defaulting to the most recent version without specifying the version number is not recommended. Please, keep in mind that we are not responsible for the correct operation of those CDN servers.
|
||||
|
||||
```HTML
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@1.38.76/dist/ccxt.browser.js"></script>
|
||||
```
|
||||
|
||||
Creates a global `ccxt` object:
|
||||
|
||||
```JavaScript
|
||||
console.log (ccxt.exchanges) // print all available exchanges
|
||||
```
|
||||
|
||||
### Python
|
||||
|
||||
[ccxt in **PyPI**](https://pypi.python.org/pypi/ccxt)
|
||||
|
||||
```shell
|
||||
pip install ccxt
|
||||
```
|
||||
|
||||
```Python
|
||||
import ccxt
|
||||
print(ccxt.exchanges) # print a list of all available exchange classes
|
||||
```
|
||||
|
||||
The library supports concurrent asynchronous mode with asyncio and async/await in Python 3.5.3+
|
||||
|
||||
```Python
|
||||
import ccxt.async_support as ccxt # link against the asynchronous version of ccxt
|
||||
```
|
||||
|
||||
### PHP
|
||||
|
||||
[ccxt in PHP with **Packagist/Composer**](https://packagist.org/packages/ccxt/ccxt) (PHP 5.4+)
|
||||
|
||||
It requires common PHP modules:
|
||||
|
||||
- cURL
|
||||
- mbstring (using UTF-8 is highly recommended)
|
||||
- PCRE
|
||||
- iconv
|
||||
- gmp (this is a built-in extension as of PHP 7.2+)
|
||||
|
||||
```PHP
|
||||
include "ccxt.php";
|
||||
var_dump (\ccxt\Exchange::$exchanges); // print a list of all available exchange classes
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
You can get CCXT installed in a container along with all the supported languages and dependencies. This may be useful if you want to contribute to CCXT (e.g. run the build scripts and tests — please see the [Contributing](https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md) document for the details on that).
|
||||
|
||||
Using `docker-compose` (in the cloned CCXT repository):
|
||||
|
||||
```shell
|
||||
docker-compose run --rm ccxt
|
||||
```
|
||||
|
||||
You don't need the Docker image if you're not going to develop CCXT. If you just want to use CCXT – just install it as a regular package into your project.
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
Read the [Manual](https://github.com/ccxt/ccxt/wiki) for more details.
|
||||
|
||||
## Usage
|
||||
|
||||
### Intro
|
||||
|
||||
The CCXT library consists of a public part and a private part. Anyone can use the public part immediately after installation. Public APIs provide unrestricted access to public information for all exchange markets without the need to register a user account or have an API key.
|
||||
|
||||
Public APIs include the following:
|
||||
|
||||
- market data
|
||||
- instruments/trading pairs
|
||||
- price feeds (exchange rates)
|
||||
- order books
|
||||
- trade history
|
||||
- tickers
|
||||
- OHLC(V) for charting
|
||||
- other public endpoints
|
||||
|
||||
In order to trade with private APIs you need to obtain API keys from an exchange's website. It usually means signing up to the exchange and creating API keys for your account. Some exchanges require personal info or identification. Sometimes verification may be necessary as well. In this case you will need to register yourself, this library will not create accounts or API keys for you. Some exchanges expose API endpoints for registering an account, but most exchanges don't. You will have to sign up and create API keys on their websites.
|
||||
|
||||
Private APIs allow the following:
|
||||
|
||||
- manage personal account info
|
||||
- query account balances
|
||||
- trade by making market and limit orders
|
||||
- deposit and withdraw fiat and crypto funds
|
||||
- query personal orders
|
||||
- get ledger history
|
||||
- transfer funds between accounts
|
||||
- use merchant services
|
||||
|
||||
This library implements full public and private REST APIs for all exchanges. WebSocket and FIX implementations in JavaScript, PHP, Python are available in [CCXT Pro](https://ccxt.pro), which is a professional addon to CCXT with support for WebSocket streams.
|
||||
|
||||
The CCXT library supports both camelcase notation (preferred in JavaScript) and underscore notation (preferred in Python and PHP), therefore all methods can be called in either notation or coding style in any language.
|
||||
|
||||
```JavaScript
|
||||
// both of these notations work in JavaScript/Python/PHP
|
||||
exchange.methodName () // camelcase pseudocode
|
||||
exchange.method_name () // underscore pseudocode
|
||||
```
|
||||
|
||||
Read the [Manual](https://github.com/ccxt/ccxt/wiki) for more details.
|
||||
|
||||
### JavaScript
|
||||
|
||||
```JavaScript
|
||||
'use strict';
|
||||
const ccxt = require ('ccxt');
|
||||
|
||||
(async function () {
|
||||
let kraken = new ccxt.kraken ()
|
||||
let bitfinex = new ccxt.bitfinex ({ verbose: true })
|
||||
let huobipro = new ccxt.huobipro ()
|
||||
let okcoinusd = new ccxt.okcoinusd ({
|
||||
apiKey: 'YOUR_PUBLIC_API_KEY',
|
||||
secret: 'YOUR_SECRET_PRIVATE_KEY',
|
||||
})
|
||||
|
||||
const exchangeId = 'binance'
|
||||
, exchangeClass = ccxt[exchangeId]
|
||||
, exchange = new exchangeClass ({
|
||||
'apiKey': 'YOUR_API_KEY',
|
||||
'secret': 'YOUR_SECRET',
|
||||
'timeout': 30000,
|
||||
'enableRateLimit': true,
|
||||
})
|
||||
|
||||
console.log (kraken.id, await kraken.loadMarkets ())
|
||||
console.log (bitfinex.id, await bitfinex.loadMarkets ())
|
||||
console.log (huobipro.id, await huobipro.loadMarkets ())
|
||||
|
||||
console.log (kraken.id, await kraken.fetchOrderBook (kraken.symbols[0]))
|
||||
console.log (bitfinex.id, await bitfinex.fetchTicker ('BTC/USD'))
|
||||
console.log (huobipro.id, await huobipro.fetchTrades ('ETH/USDT'))
|
||||
|
||||
console.log (okcoinusd.id, await okcoinusd.fetchBalance ())
|
||||
|
||||
// sell 1 BTC/USD for market price, sell a bitcoin for dollars immediately
|
||||
console.log (okcoinusd.id, await okcoinusd.createMarketSellOrder ('BTC/USD', 1))
|
||||
|
||||
// buy 1 BTC/USD for $2500, you pay $2500 and receive ฿1 when the order is closed
|
||||
console.log (okcoinusd.id, await okcoinusd.createLimitBuyOrder ('BTC/USD', 1, 2500.00))
|
||||
|
||||
// pass/redefine custom exchange-specific order params: type, amount, price or whatever
|
||||
// use a custom order type
|
||||
bitfinex.createLimitSellOrder ('BTC/USD', 1, 10, { 'type': 'trailing-stop' })
|
||||
|
||||
}) ();
|
||||
```
|
||||
|
||||
### Python
|
||||
|
||||
```Python
|
||||
# coding=utf-8
|
||||
|
||||
import ccxt
|
||||
|
||||
hitbtc = ccxt.hitbtc({'verbose': True})
|
||||
bitmex = ccxt.bitmex()
|
||||
huobipro = ccxt.huobipro()
|
||||
exmo = ccxt.exmo({
|
||||
'apiKey': 'YOUR_PUBLIC_API_KEY',
|
||||
'secret': 'YOUR_SECRET_PRIVATE_KEY',
|
||||
})
|
||||
kraken = ccxt.kraken({
|
||||
'apiKey': 'YOUR_PUBLIC_API_KEY',
|
||||
'secret': 'YOUR_SECRET_PRIVATE_KEY',
|
||||
})
|
||||
|
||||
exchange_id = 'binance'
|
||||
exchange_class = getattr(ccxt, exchange_id)
|
||||
exchange = exchange_class({
|
||||
'apiKey': 'YOUR_API_KEY',
|
||||
'secret': 'YOUR_SECRET',
|
||||
'timeout': 30000,
|
||||
'enableRateLimit': True,
|
||||
})
|
||||
|
||||
hitbtc_markets = hitbtc.load_markets()
|
||||
|
||||
print(hitbtc.id, hitbtc_markets)
|
||||
print(bitmex.id, bitmex.load_markets())
|
||||
print(huobipro.id, huobipro.load_markets())
|
||||
|
||||
print(hitbtc.fetch_order_book(hitbtc.symbols[0]))
|
||||
print(bitmex.fetch_ticker('BTC/USD'))
|
||||
print(huobipro.fetch_trades('LTC/USDT'))
|
||||
|
||||
print(exmo.fetch_balance())
|
||||
|
||||
# sell one ฿ for market price and receive $ right now
|
||||
print(exmo.id, exmo.create_market_sell_order('BTC/USD', 1))
|
||||
|
||||
# limit buy BTC/EUR, you pay €2500 and receive ฿1 when the order is closed
|
||||
print(exmo.id, exmo.create_limit_buy_order('BTC/EUR', 1, 2500.00))
|
||||
|
||||
# pass/redefine custom exchange-specific order params: type, amount, price, flags, etc...
|
||||
kraken.create_market_buy_order('BTC/USD', 1, {'trading_agreement': 'agree'})
|
||||
```
|
||||
|
||||
### PHP
|
||||
|
||||
```PHP
|
||||
include 'ccxt.php';
|
||||
|
||||
$poloniex = new \ccxt\poloniex ();
|
||||
$bittrex = new \ccxt\bittrex (array ('verbose' => true));
|
||||
$quoinex = new \ccxt\quoinex ();
|
||||
$zaif = new \ccxt\zaif (array (
|
||||
'apiKey' => 'YOUR_PUBLIC_API_KEY',
|
||||
'secret' => 'YOUR_SECRET_PRIVATE_KEY',
|
||||
));
|
||||
$hitbtc = new \ccxt\hitbtc (array (
|
||||
'apiKey' => 'YOUR_PUBLIC_API_KEY',
|
||||
'secret' => 'YOUR_SECRET_PRIVATE_KEY',
|
||||
));
|
||||
|
||||
$exchange_id = 'binance';
|
||||
$exchange_class = "\\ccxt\\$exchange_id";
|
||||
$exchange = new $exchange_class (array (
|
||||
'apiKey' => 'YOUR_API_KEY',
|
||||
'secret' => 'YOUR_SECRET',
|
||||
'timeout' => 30000,
|
||||
'enableRateLimit' => true,
|
||||
));
|
||||
|
||||
$poloniex_markets = $poloniex->load_markets ();
|
||||
|
||||
var_dump ($poloniex_markets);
|
||||
var_dump ($bittrex->load_markets ());
|
||||
var_dump ($quoinex->load_markets ());
|
||||
|
||||
var_dump ($poloniex->fetch_order_book ($poloniex->symbols[0]));
|
||||
var_dump ($bittrex->fetch_trades ('BTC/USD'));
|
||||
var_dump ($quoinex->fetch_ticker ('ETH/EUR'));
|
||||
var_dump ($zaif->fetch_ticker ('BTC/JPY'));
|
||||
|
||||
var_dump ($zaif->fetch_balance ());
|
||||
|
||||
// sell 1 BTC/JPY for market price, you pay ¥ and receive ฿ immediately
|
||||
var_dump ($zaif->id, $zaif->create_market_sell_order ('BTC/JPY', 1));
|
||||
|
||||
// buy BTC/JPY, you receive ฿1 for ¥285000 when the order closes
|
||||
var_dump ($zaif->id, $zaif->create_limit_buy_order ('BTC/JPY', 1, 285000));
|
||||
|
||||
// set a custom user-defined id to your order
|
||||
$hitbtc->create_order ('BTC/USD', 'limit', 'buy', 1, 3000, array ('clientOrderId' => '123'));
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Please read the [CONTRIBUTING](https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md) document before making changes that you would like adopted in the code. Also, read the [Manual](https://github.com/ccxt/ccxt/wiki) for more details.
|
||||
|
||||
## Support Developer Team
|
||||
|
||||
We are investing a significant amount of time into the development of this library. If CCXT made your life easier and you want to help us improve it further, or if you want to speed up development of new features and exchanges, please support us with a tip. We appreciate all contributions!
|
||||
|
||||
### Sponsors
|
||||
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website.
|
||||
|
||||
[[Become a sponsor](https://opencollective.com/ccxt#sponsor)]
|
||||
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/sponsor/9/avatar.svg"></a>
|
||||
|
||||
### Supporters
|
||||
|
||||
Support this project by becoming a supporter. Your avatar will show up here with a link to your website.
|
||||
|
||||
[[Become a supporter](https://opencollective.com/ccxt#supporter)]
|
||||
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/0/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/1/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/2/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/3/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/4/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/5/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/6/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/7/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/8/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/ccxt/tiers/supporter/9/website" target="_blank"><img src="https://opencollective.com/ccxt/tiers/supporter/9/avatar.svg"></a>
|
||||
|
||||
### Backers
|
||||
|
||||
Thank you to all our backers! [[Become a backer](https://opencollective.com/ccxt#backer)]
|
||||
|
||||
<a href="https://opencollective.com/ccxt#backers" target="_blank"><img src="https://opencollective.com/ccxt/tiers/backer.svg?width=890"></a>
|
||||
|
||||
### Crypto
|
||||
|
||||
```
|
||||
ETH 0x26a3CB49578F07000575405a57888681249c35Fd (ETH only)
|
||||
BTC 33RmVRfhK2WZVQR1R83h2e9yXoqRNDvJva
|
||||
BCH 1GN9p233TvNcNQFthCgfiHUnj5JRKEc2Ze
|
||||
LTC LgM5hkvPzytEFfQGGDFGKYkE743jwUA7qv
|
||||
```
|
||||
|
||||
Thank you!
|
||||
|
||||
## Social
|
||||
|
||||
- [Follow us on Twitter](https://twitter.com/ccxt_official)
|
||||
- [Read our blog on Medium](https://medium.com/@ccxt)
|
||||
- <sub><sub>[](https://discord.gg/dhzSKYU)</sub></sub>
|
||||
|
||||
## Contact Us
|
||||
|
||||
For business inquiries: info@ccxt.trade
|
||||