Merge remote-tracking branch 'OneMinCandles/develop' into develop
This commit is contained in:
commit
30d5bdf323
11 files changed
+1247
No files matched your search
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
|
||||
.vs/*
|
||||
obj/*
|
||||
|
||||
bin/*
|
||||
|
||||
*.config
|
||||
*.log
|
||||
*.cache
|
||||
node_modules/*
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2027
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "Project", "Project.njsproj", "{045BBAEF-3C35-4017-8458-E46AEF438790}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{045BBAEF-3C35-4017-8458-E46AEF438790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{045BBAEF-3C35-4017-8458-E46AEF438790}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{045BBAEF-3C35-4017-8458-E46AEF438790}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{045BBAEF-3C35-4017-8458-E46AEF438790}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {2A5094EC-199A-4833-894F-166CB38B4715}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
exports.newCommons = function newCommons(bot, logger, UTILITIES) {
|
||||
|
||||
const FULL_LOG = true;
|
||||
const LOG_FILE_CONTENT = false;
|
||||
|
||||
const MODULE_NAME = "Commons";
|
||||
|
||||
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
|
||||
const GMT_SECONDS = ':00.000 GMT+0000';
|
||||
|
||||
let thisObject = {
|
||||
initializeStorage: initializeStorage
|
||||
};
|
||||
|
||||
let utilities = UTILITIES.newCloudUtilities(bot, logger);
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initializeStorage(charlyStorage, bruceStorage, callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initializeStorage -> Entering function."); }
|
||||
|
||||
initializeBruceStorage();
|
||||
|
||||
function initializeBruceStorage() {
|
||||
|
||||
bruceStorage.initialize(bot.dataMine, onBruceInizialized);
|
||||
|
||||
function onBruceInizialized(err) {
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
initializeCharlyStorage();
|
||||
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializeBruceStorage -> onBruceInizialized -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initializeCharlyStorage() {
|
||||
|
||||
charlyStorage.initialize(bot.dataMine, onCharlyInizialized);
|
||||
|
||||
function onCharlyInizialized(err) {
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] initializeStorage -> initializeCharlyStorage -> onCharlyInizialized -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] initializeStorage -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
Financial Beings License
|
||||
|
||||
Collective Copyright by the Advanced Algos Community
|
||||
|
||||
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 including without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute and sublicense copies of the Software, and to permit
|
||||
persons to whom the Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
1. Using, copying, modifying, publishing, distributing and sublicensing rights
|
||||
are restricted to the Advanced Algos Platform, meaning the rights granted can
|
||||
only be exercised through the Advanced Algos Service.
|
||||
|
||||
2. 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,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{045bbaef-3c35-4017-8458-e46aef438790}</ProjectGuid>
|
||||
<ProjectHome />
|
||||
<ProjectView>ShowAllFiles</ProjectView>
|
||||
<StartupFile>
|
||||
</StartupFile>
|
||||
<WorkingDirectory>C:\Users\Luis\source\repos\AABruce\One-Min-Daily-Candles-Volumes</WorkingDirectory>
|
||||
<OutputPath>.</OutputPath>
|
||||
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<Name>Project</Name>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Debug'" />
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'" />
|
||||
<ItemGroup>
|
||||
<Content Include="README.md" />
|
||||
<Compile Include="Commons.js">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Single-Period-Daily\User.Bot.js" />
|
||||
<Content Include="obj\Debug\AACarol.njsproj.FileListAbsolute.txt" />
|
||||
<Content Include="obj\Debug\AACharly.njsproj.FileListAbsolute.txt" />
|
||||
<Content Include="this.bot.config.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="bin" />
|
||||
<Folder Include="obj" />
|
||||
<Folder Include="obj\Debug" />
|
||||
<Folder Include="Single-Period-Daily\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<!--Do not delete the following Import Project. While this appears to do nothing it is a marker for setting TypeScript properties before our import that depends on them.-->
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition="False" />
|
||||
<Import Project="$(VSToolsPath)\Node.js Tools\Microsoft.NodejsTools.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>False</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>0</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:48022/</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>True</UseCustomServer>
|
||||
<CustomServerUrl>http://localhost:1337</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}" User="">
|
||||
<WebProjectProperties>
|
||||
<StartPageUrl>
|
||||
</StartPageUrl>
|
||||
<StartAction>CurrentPage</StartAction>
|
||||
<AspNetDebugging>True</AspNetDebugging>
|
||||
<SilverlightDebugging>False</SilverlightDebugging>
|
||||
<NativeDebugging>False</NativeDebugging>
|
||||
<SQLDebugging>False</SQLDebugging>
|
||||
<ExternalProgram>
|
||||
</ExternalProgram>
|
||||
<StartExternalURL>
|
||||
</StartExternalURL>
|
||||
<StartCmdLineArguments>
|
||||
</StartCmdLineArguments>
|
||||
<StartWorkingDirectory>
|
||||
</StartWorkingDirectory>
|
||||
<EnableENC>False</EnableENC>
|
||||
<AlwaysStartWebServerOnDebug>False</AlwaysStartWebServerOnDebug>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
@@ -0,0 +1,70 @@
|
||||
# Bruce
|
||||
|
||||
Bruce is a low level Indicator bot that has as an input trades files and outputs 1 minute candles packaged on daily files.
|
||||
|
||||
## Single Period Daily
|
||||
|
||||
This process reads trades packed in 1 minutes files. For every day it creates a file with candles at 1 minute.
|
||||
|
||||
### Start Mode
|
||||
|
||||
This process runs every 1 minute under allMonths start mode, where a yearly range must be specified (initial processing year and final processing year)
|
||||
|
||||
## Dataset 1: Candles in 1 Minute Resolutions
|
||||
|
||||
### Current Dataset Scope
|
||||
* **Exchanges**: Poloniex, Coss
|
||||
* **Markets**: USDT-BTC
|
||||
* **Range**: Market Start Date – Current Time (-0 to 59 secs)
|
||||
|
||||
### Current Dataset
|
||||
* **Version:** dataSet.V1
|
||||
* **Update Frequency**: 1 minute
|
||||
* **Cloud Output Location:** AAMasters > AABruce.1.0 > AACloud.1.1 > ExchangeName > dataSet.V1
|
||||
* **Folder Structure Tree**: Output > Candles > Multi-Period-Daily > (01-min | 02-min | 03-min | 04-min | 05-min | 10-min | 15-min | 20-min | 30-min | 45-min) > Year > Month > Day > Hour > Minute
|
||||
* **Files Structure**: One .json file stored at the Minute level of the Folder Tree Structure
|
||||
* **In-File Record Structure**:
|
||||
* Minimum, decimal;
|
||||
* Maximum, decimal;
|
||||
* Open, decimal;
|
||||
* Close, decimal;
|
||||
* Begin, decimal;
|
||||
* End, decimal;
|
||||
* **In-File Record Example**:
|
||||
* [[13760.00000003,13799.99999984,13799.99999984,13785.89250371,1514764800000,1514764859999],[13760,13785.89250371,13766.22307573,13785.89250322,1514764860000,1514764919999], ... ,[13760,13785.89250322,13760.00000114,13760.00000089,1514764920000,1514764979999]]
|
||||
|
||||
## Dataset 2: Volumes in 1 Minute Resolutions
|
||||
|
||||
### Current Dataset Scope
|
||||
* **Exchanges**: Poloniex, Coss
|
||||
* **Markets**: USDT-BTC
|
||||
* **Range**: Market Start Date – Current Time (-0 to 59 secs)
|
||||
|
||||
### Current Dataset
|
||||
* **Version:** dataSet.V1
|
||||
* **Update Frequency**: 1 minute
|
||||
* **Cloud Output Location:** AAMasters > AACloud.1.1 > ExchangeName > dataSet.V1
|
||||
* **Folder Structure Tree**: Output > Volumes > Multi-Period-Daily > (01-min | 02-min | 03-min | 04-min | 05-min | 10-min | 15-min | 20-min | 30-min | 45-min) > Year > Month > Day > Hour > Minute
|
||||
* **Files Structure**: One .json file stored at the Minute level of the Folder Tree Structure
|
||||
* **In-File Record Structure**:
|
||||
* Buy Volume, decimal;
|
||||
* Sell Volume, decimal;
|
||||
* Open Volume, decimal;
|
||||
* Close Volume, decimal
|
||||
* **In-File Record Example**:
|
||||
* [[7412.27033867,7414.5873403,7414.57532252,7414.5873403],[7390.42410104,7414.5873403,7412.06261697,7390.42410104], ... ,[7390,7392.88810353,7392.88810353,7390]]
|
||||
|
||||
### Compatible Plotters
|
||||
[AAMasters Plotters-Candles-Volumes](https://github.com/AAMasters/Plotters-Candles-Volumes)
|
||||
|
||||
### Dependencies
|
||||
[AAMasters Charly](https://github.com/AAMasters/AACharly-Extraction-Bot)
|
||||
|
||||
### Data as a Service (DaaS) Fees
|
||||
No fees.
|
||||
|
||||
# Disclaimer
|
||||
|
||||
THE AA MASTERS BOTS AND THEIR ASSOCIATED PRODUCTS AND SERVICES ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, SUITABILITY FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
|
||||
|
||||
IN NO EVENT WILL ADVANCED ALGOS BE LIABLE TO ANY PARTY FOR ANY DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY USE OF THE AACLOUD, THE AA ARENA COMPETITION, THE AA MASTERS BOTS, OR ANY OTHER ASSOCIATED SERVICE OR WEB SITE, INCLUDING, WITHOUT LIMITATION, ANY LOST PROFITS, BUSINESS INTERRUPTION, LOSS OF FUNDS, PROGRAMS OR OTHER DATA OR OTHERWISE, EVEN IF WE ARE EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
@@ -0,0 +1,814 @@
|
||||
exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, fileStorage) {
|
||||
|
||||
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 statusDependencies;
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
|
||||
statusDependencies = pStatusDependencies;
|
||||
|
||||
logger.fileName = MODULE_NAME
|
||||
logger.initialize();
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
This process is going to do the following:
|
||||
Read the trades from Charly's Output and pack them into daily files with candles of one minute.
|
||||
*/
|
||||
|
||||
function start(callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
|
||||
|
||||
let processDate = new Date((new Date()).getUTCFullYear() + "-" + ((new Date()).getUTCMonth() + 1) + "-1 00:00:00.000 GMT+0000");
|
||||
|
||||
let thisDatetime = new Date();
|
||||
|
||||
let market = bot.market;
|
||||
|
||||
let lastTradeFileProcessed; // Datetime of the last file certified by the Hole Fixing process as without permanent holes.
|
||||
let firstTradeFile; // Datetime of the first trade file in the whole market history.
|
||||
let lastTradeFileSaved; // Datetime of the last verified file without holes.
|
||||
let lastCandleClose; // Value of the last candle close.
|
||||
let lastTradeFile; // Datetime pointing to the last Trade File sucessfuly processed and included in the last file.
|
||||
let beginingOfMarket
|
||||
|
||||
getContextVariables();
|
||||
|
||||
function getContextVariables() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Entering function."); }
|
||||
|
||||
let thisReport;
|
||||
let reportKey;
|
||||
|
||||
/* First Status Report */
|
||||
reportKey = "AAMasters" + "-" + "AACharly" + "-" + "Historic-Trades" + "-" + "dataSet.V1";
|
||||
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).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;
|
||||
}
|
||||
|
||||
firstTradeFile = new Date(thisReport.beginingOfMarket.year + "-" + thisReport.beginingOfMarket.month + "-" + thisReport.beginingOfMarket.days + " " + thisReport.beginingOfMarket.hours + ":" + thisReport.beginingOfMarket.minutes + GMT_SECONDS);
|
||||
lastTradeFileSaved = new Date(thisReport.lastFileSaved.year + "-" + thisReport.lastFileSaved.month + "-" + thisReport.lastFileSaved.days + " " + thisReport.lastFileSaved.hours + ":" + thisReport.lastFileSaved.minutes + GMT_SECONDS);
|
||||
|
||||
/* Final Status Report */
|
||||
|
||||
reportKey = "AAMasters" + "-" + "AABruce" + "-" + "Single-Period-Daily" + "-" + "dataSet.V1"
|
||||
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 self dependecy Status Report is corrupt. Aborting Process.");
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
||||
|
||||
if (thisReport.lastFile === undefined) { // Means this is the first time ever this process runs.
|
||||
logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Process Running for the very first time. -> reportKey = " + reportKey);
|
||||
|
||||
lastCandleClose = 0;
|
||||
lastTradeFileProcessed = new Date(firstTradeFile.valueOf() - ONE_DAY_IN_MILISECONDS)
|
||||
beginingOfMarket = new Date(firstTradeFile.valueOf())
|
||||
|
||||
buildCandlesAndVolumes();
|
||||
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Process Running not for the very first time. -> reportKey = " + reportKey);
|
||||
|
||||
lastTradeFileProcessed = new Date(thisReport.lastTradeFile.year + "-" + thisReport.lastTradeFile.month + "-" + thisReport.lastTradeFile.days + " " + "00:00" + GMT_SECONDS);
|
||||
lastCandleClose = thisReport.candleClose;
|
||||
beginingOfMarket = new Date(thisReport.beginingOfMarket.year + "-" + thisReport.beginingOfMarket.month + "-" + thisReport.beginingOfMarket.days + " " + thisReport.beginingOfMarket.hours + ":" + thisReport.beginingOfMarket.minutes + GMT_SECONDS);
|
||||
|
||||
if (beginingOfMarket.valueOf() !== 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(firstTradeFile.valueOf())
|
||||
lastTradeFileProcessed = new Date(firstTradeFile.valueOf() - ONE_DAY_IN_MILISECONDS)
|
||||
lastCandleClose = 0
|
||||
buildCandlesAndVolumes()
|
||||
return
|
||||
}
|
||||
|
||||
if (thisReport.fileComplete === true) {
|
||||
buildCandlesAndVolumes();
|
||||
} else {
|
||||
lastTradeFile = new Date(thisReport.lastTradeFile.year + "-" + thisReport.lastTradeFile.month + "-" + thisReport.lastTradeFile.days + " " + thisReport.lastTradeFile.hours + ":" + thisReport.lastTradeFile.minutes + GMT_SECONDS);
|
||||
findPreviousContent();
|
||||
}
|
||||
}
|
||||
} 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 findPreviousContent() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> Entering function."); }
|
||||
|
||||
let previousCandles;
|
||||
let previousVolumes;
|
||||
|
||||
getCandles();
|
||||
|
||||
function getCandles() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> getCandles -> Entering function."); }
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let dateForPath = lastTradeFileProcessed.getUTCFullYear() + '/' + utilities.pad(lastTradeFileProcessed.getUTCMonth() + 1, 2) + '/' + utilities.pad(lastTradeFileProcessed.getUTCDate(), 2);
|
||||
let filePath = bot.filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + CANDLES_ONE_MIN + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> getCandles -> reading file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
let candlesFile;
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> getCandles -> onFileReceived -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> getCandles -> onFileReceived -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> getCandles -> onFileReceived -> text = " + text);
|
||||
}
|
||||
|
||||
candlesFile = JSON.parse(text);
|
||||
previousCandles = candlesFile;
|
||||
getVolumes();
|
||||
|
||||
} catch (err) {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> getCandles -> onFileReceived -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> getCandles -> onFileReceived -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[HINT] start -> findPreviousContent -> getCandles -> onFileReceived -> Empty or corrupt volume file found.");
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> getCandles -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function getVolumes() {
|
||||
|
||||
try {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> getVolumes -> Entering function."); }
|
||||
|
||||
let fileName = 'Data.json';
|
||||
let dateForPath = lastTradeFileProcessed.getUTCFullYear() + '/' + utilities.pad(lastTradeFileProcessed.getUTCMonth() + 1, 2) + '/' + utilities.pad(lastTradeFileProcessed.getUTCDate(), 2);
|
||||
let filePath = bot.filePathRoot + "/Output/" + VOLUMES_FOLDER_NAME + '/' + VOLUMES_ONE_MIN + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> getVolumes -> reading file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
let volumesFile;
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> getVolumes -> onFileReceived -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> getVolumes -> onFileReceived -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> getVolumes -> onFileReceived -> text = " + text);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> findPreviousContent -> getVolumes -> onFileReceived -> text = " + text);
|
||||
}
|
||||
|
||||
volumesFile = JSON.parse(text);
|
||||
previousVolumes = volumesFile;
|
||||
lastTradeFileProcessed = new Date(lastTradeFileProcessed.valueOf() - ONE_DAY_IN_MILISECONDS); // We know that after the next call a new day will be added.
|
||||
buildCandlesAndVolumes(previousCandles, previousVolumes);
|
||||
|
||||
} catch (err) {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> getVolumes -> onFileReceived -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> getVolumes -> onFileReceived -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> getVolumes -> onFileReceived -> text = " + text);
|
||||
logger.write(MODULE_NAME, "[HINT] start -> findPreviousContent -> getVolumes -> onFileReceived -> Empty or corrupt volume file found.");
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> getVolumes -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> findPreviousContent -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function buildCandlesAndVolumes(previousCandles, previousVolumes) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> Entering function."); }
|
||||
|
||||
/*
|
||||
Here we are going to scan the trades files packing them in candles files every one day.
|
||||
We need for this the last close value, bacause all candles that are empty of trades at the begining, they need to
|
||||
have a valid open and close value. This was previously calculated before arriving to this function.
|
||||
*/
|
||||
|
||||
let canAddPrevious = true;
|
||||
|
||||
try {
|
||||
nextFile();
|
||||
|
||||
function nextFile() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> Entering function."); }
|
||||
|
||||
lastTradeFileProcessed = new Date(lastTradeFileProcessed.valueOf() + ONE_DAY_IN_MILISECONDS);
|
||||
|
||||
let date = new Date(lastTradeFileProcessed.valueOf() - 60 * 1000);
|
||||
|
||||
if (date.valueOf() < firstTradeFile.valueOf()) { // At the special case where we are at the begining of the market, this might be true.
|
||||
date = new Date(firstTradeFile.valueOf() - 60 * 1000);
|
||||
}
|
||||
|
||||
if (lastTradeFile !== undefined) {
|
||||
date = new Date(lastTradeFile.valueOf());
|
||||
}
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> date = " + date); }
|
||||
|
||||
let candles = [];
|
||||
let volumes = [];
|
||||
|
||||
if (previousCandles !== undefined && canAddPrevious === true) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> Adding Previous Candles. "); }
|
||||
|
||||
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]
|
||||
};
|
||||
|
||||
candles.push(candle);
|
||||
}
|
||||
}
|
||||
|
||||
if (previousVolumes !== undefined && canAddPrevious === true) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> Adding Previous Volumes. "); }
|
||||
|
||||
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]
|
||||
};
|
||||
|
||||
volumes.push(volume);
|
||||
}
|
||||
}
|
||||
|
||||
canAddPrevious = false; // We add them only onece.
|
||||
|
||||
nextDate();
|
||||
|
||||
function nextDate() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> nextDate -> Entering function."); }
|
||||
|
||||
date = new Date(date.valueOf() + 60 * 1000);
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> nextDate -> date = " + date); }
|
||||
|
||||
/* Check if we are outside the current Day / File */
|
||||
|
||||
if (date.getUTCDate() !== lastTradeFileProcessed.getUTCDate()) {
|
||||
|
||||
writeFiles(lastTradeFileProcessed, candles, volumes, true, onFilesWritten);
|
||||
|
||||
return;
|
||||
|
||||
function onFilesWritten() {
|
||||
|
||||
nextFile();
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we have past the most recent hole fixed file */
|
||||
|
||||
if (date.valueOf() > lastTradeFileSaved.valueOf()) {
|
||||
|
||||
writeFiles(lastTradeFileProcessed, candles, volumes, false, onFilesWritten);
|
||||
return;
|
||||
|
||||
function onFilesWritten() {
|
||||
|
||||
if (FULL_LOG === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> nextDate -> Head of the market reached for market " + market.baseAsset + '_' + market.quotedAsset + ".");
|
||||
}
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
readTrades();
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandlesAndVolumes -> nextFile -> nextDate -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function readTrades() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> nextDate -> readTrades -> Entering function."); }
|
||||
|
||||
lastTradeFile = new Date(date.valueOf());
|
||||
|
||||
let dateForPath = date.getUTCFullYear() + '/' + utilities.pad(date.getUTCMonth() + 1, 2) + '/' + utilities.pad(date.getUTCDate(), 2) + '/' + utilities.pad(date.getUTCHours(), 2) + '/' + utilities.pad(date.getUTCMinutes(), 2);
|
||||
let fileName = "Data.json"
|
||||
let filePathRoot = bot.exchange + "/" + bot.market.baseAsset + "-" + bot.market.quotedAsset + "/" + bot.dataMine + "/" + "AACharly";
|
||||
|
||||
let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.getTextFile(filePath, onFileReceived);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> nextDate -> readTrades -> reading file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
let tradesFile;
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> readTrades -> onFileReceived -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandlesAndVolumes -> nextFile -> readTrades -> onFileReceived -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandlesAndVolumes -> nextFile -> readTrades -> onFileReceived -> text = " + text);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_FILE_CONTENT === true) {
|
||||
logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> readTrades -> onFileReceived -> text = " + text);
|
||||
}
|
||||
|
||||
let candle = {
|
||||
open: lastCandleClose,
|
||||
close: lastCandleClose,
|
||||
min: lastCandleClose,
|
||||
max: lastCandleClose,
|
||||
begin: date.valueOf(),
|
||||
end: date.valueOf() + 60 * 1000 - 1
|
||||
};
|
||||
|
||||
let volume = {
|
||||
begin: date.valueOf(),
|
||||
end: date.valueOf() + 60 * 1000 - 1,
|
||||
buy: 0,
|
||||
sell: 0
|
||||
};
|
||||
|
||||
tradesFile = JSON.parse(text);
|
||||
|
||||
let tradesCount = utilities.pad(tradesFile.length, 5);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> buildCandlesAndVolumes -> nextFile -> readTrades -> onFileReceived -> " + tradesCount + " trades found at " + filePath + " for market " + market.baseAsset + '_' + market.quotedAsset + ". ");
|
||||
|
||||
if (tradesFile.length > 0) {
|
||||
|
||||
/* Candle open and close Calculations */
|
||||
|
||||
candle.open = tradesFile[0][2];
|
||||
candle.close = tradesFile[tradesFile.length - 1][2];
|
||||
lastCandleClose = candle.close;
|
||||
}
|
||||
|
||||
for (let i = 0; i < tradesFile.length; i++) {
|
||||
|
||||
let record = {
|
||||
side: tradesFile[i][1],
|
||||
price: tradesFile[i][2],
|
||||
amount: tradesFile[i][3]
|
||||
};
|
||||
|
||||
let trade = {
|
||||
type: record.side,
|
||||
rate: record.price,
|
||||
amountA: record.amount,
|
||||
amountB: record.amount * record.price
|
||||
};
|
||||
|
||||
/* Candle min and max Calculations */
|
||||
|
||||
if (trade.rate < candle.min) {
|
||||
candle.min = trade.rate;
|
||||
}
|
||||
|
||||
if (trade.rate > candle.max) {
|
||||
candle.max = trade.rate;
|
||||
}
|
||||
|
||||
/* Volume Calculations */
|
||||
|
||||
if (trade.type === "sell") {
|
||||
volume.sell = volume.sell + trade.amountA;
|
||||
} else {
|
||||
volume.buy = volume.buy + trade.amountA;
|
||||
}
|
||||
}
|
||||
|
||||
candles.push(candle);
|
||||
volumes.push(volume);
|
||||
nextDate();
|
||||
|
||||
} catch (err) {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandlesAndVolumes -> nextFile -> readTrades -> onFileReceived -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandlesAndVolumes -> nextFile -> readTrades -> onFileReceived -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandlesAndVolumes -> nextFile -> readTrades -> onFileReceived -> text = " + text);
|
||||
logger.write(MODULE_NAME, "[HINT] start -> buildCandlesAndVolumes -> nextFile -> readTrades -> onFileReceived -> Empty or corrupt volume file found.");
|
||||
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandlesAndVolumes -> nextFile -> readTrades -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandlesAndVolumes -> nextFile -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> buildCandlesAndVolumes -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeFiles(date, candles, volumes, isFileComplete, 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. If the File is declared as complete, we will also write the status report.
|
||||
*/
|
||||
|
||||
try {
|
||||
|
||||
writeCandles();
|
||||
|
||||
function writeCandles() {
|
||||
|
||||
try {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
|
||||
let fileContent = "";
|
||||
|
||||
for (i = 0; i < candles.length; 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 = date.getUTCFullYear() + '/' + utilities.pad(date.getUTCMonth() + 1, 2) + '/' + utilities.pad(date.getUTCDate(), 2);
|
||||
let filePath = bot.filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + CANDLES_ONE_MIN + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> writing file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
try {
|
||||
|
||||
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 -> fileContent = " + fileContent);
|
||||
}
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeCandles -> onFileCreated -> Finished with File @ " + market.baseAsset + "_" + market.quotedAsset + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName + "");
|
||||
|
||||
writeVolumes();
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeCandles -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeCandles -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeVolumes() {
|
||||
|
||||
try {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> Entering function."); }
|
||||
|
||||
let separator = "";
|
||||
let fileRecordCounter = 0;
|
||||
|
||||
let fileContent = "";
|
||||
|
||||
for (i = 0; i < volumes.length; i++) {
|
||||
|
||||
/* Validation trying to find a BUG that changes the dates of rubish data. */
|
||||
|
||||
if (volumes[i].begin < 1262304000000 | volumes[i].end < 1262304000000) { // If it is storing a number that represents a date before the year 2010...
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeVolumes -> Invalid Date trying to be recorded on output file. ");
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeVolumes -> volumes[i].begin = " + volumes[i].begin);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeVolumes -> volumes[i].end = " + volumes[i].end);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeVolumes -> i = " + i);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeVolumes -> volumes = " + JSON.stringify(volumes));
|
||||
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
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 = date.getUTCFullYear() + '/' + utilities.pad(date.getUTCMonth() + 1, 2) + '/' + utilities.pad(date.getUTCDate(), 2);
|
||||
let filePath = bot.filePathRoot + "/Output/" + VOLUMES_FOLDER_NAME + '/' + VOLUMES_ONE_MIN + '/' + dateForPath;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> writing file at dateForPath = " + dateForPath);
|
||||
|
||||
function onFileCreated(err) {
|
||||
|
||||
try {
|
||||
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 -> fileContent = " + fileContent);
|
||||
}
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeVolumes -> onFileCreated -> Finished with File @ " + market.baseAsset + "_" + market.quotedAsset + ", " + fileRecordCounter + " records inserted into " + filePath + "/" + fileName + "");
|
||||
|
||||
writeReport();
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeVolumes -> onFileCreated -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeVolumes -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeReport() {
|
||||
|
||||
try {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeReport -> Entering function."); }
|
||||
|
||||
writeStatusReport(date, lastTradeFile, lastCandleClose, isFileComplete, false, onStatusReportWritten);
|
||||
|
||||
function onStatusReportWritten(err) {
|
||||
|
||||
try {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeFiles -> writeReport -> onStatusReportWritten -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> onStatusReportWritten -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
callBack();
|
||||
return;
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeReport -> onStatusReportWritten -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> writeReport -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeFiles -> err = " + err.stack);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function writeStatusReport(lastFileDate, lastTradeFile, candleClose, isFileComplete, isMonthComplete, 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); }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> lastTradeFile = " + lastTradeFile); }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> candleClose = " + candleClose); }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> isFileComplete = " + isFileComplete); }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> isMonthComplete = " + isMonthComplete); }
|
||||
|
||||
try {
|
||||
|
||||
if (lastTradeFile === undefined) {
|
||||
|
||||
/* At the begining of a new month, it can happen for reasons not 100% clear that this variable gets undifined.
|
||||
Probably it is because the instance that was waiting to execute in coma state, wakes up before than Charly
|
||||
writting the trades of this new month. Anyway, when this happens, a different path in code is taken and this
|
||||
variable gets undefined. A workaround for that without further investigation of the real cause of the problem
|
||||
is to RETRY the execution until the normal conditions arise and everything continues working well. That is what
|
||||
we are going to do for now. */
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] start -> writeStatusReport -> Cannot write the status report."); }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[WARN] start -> writeStatusReport -> lastTradeFile = undefined."); }
|
||||
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let key = bot.dataMine + "-" + bot.codeName + "-" + bot.process + "-" + bot.dataSetVersion
|
||||
let statusReport = statusDependencies.statusReports.get(key);
|
||||
|
||||
statusReport.file = {
|
||||
lastFile: {
|
||||
year: lastFileDate.getUTCFullYear(),
|
||||
month: (lastFileDate.getUTCMonth() + 1),
|
||||
days: lastFileDate.getUTCDate()
|
||||
},
|
||||
lastTradeFile: {
|
||||
year: lastTradeFile.getUTCFullYear(),
|
||||
month: (lastTradeFile.getUTCMonth() + 1),
|
||||
days: lastTradeFile.getUTCDate(),
|
||||
hours: lastTradeFile.getUTCHours(),
|
||||
minutes: lastTradeFile.getUTCMinutes()
|
||||
},
|
||||
beginingOfMarket: {
|
||||
year: beginingOfMarket.getUTCFullYear(),
|
||||
month: (beginingOfMarket.getUTCMonth() + 1),
|
||||
days: beginingOfMarket.getUTCDate(),
|
||||
hours: beginingOfMarket.getUTCHours(),
|
||||
minutes: beginingOfMarket.getUTCMinutes()
|
||||
},
|
||||
candleClose: candleClose,
|
||||
fileComplete: isFileComplete
|
||||
};
|
||||
|
||||
let fileContent = JSON.stringify(statusReport);
|
||||
|
||||
statusReport.save(onSaved);
|
||||
|
||||
function onSaved(err) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> onSaved -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> onSaved -> err = " + err.stack);
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
callBack(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);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "AABruce",
|
||||
"version": "1.0.0",
|
||||
"description": "Processes that get the order books from Poloniex.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Luis-Fernando-Molina",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"displayName": "Bruce",
|
||||
"codeName": "AABruce",
|
||||
"type": "Indicator Bot",
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0,
|
||||
"patch": 0
|
||||
},
|
||||
"dataMine": "AAMasters",
|
||||
"profilePicture": "Bruce.png",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"processes": [
|
||||
{
|
||||
"name": "Single-Period-Daily",
|
||||
"description": "Produces two data-sets with candles and volumes.",
|
||||
"startMode": {
|
||||
"allMonths": {
|
||||
"run": "true",
|
||||
"minYear": "2019",
|
||||
"maxYear": "2019"
|
||||
},
|
||||
"oneMonth": {
|
||||
"run": "false",
|
||||
"year": "2018",
|
||||
"month": "6"
|
||||
},
|
||||
"noTime": {
|
||||
"run": "false"
|
||||
},
|
||||
"fixedInterval": {
|
||||
"run": "false",
|
||||
"interval": 0
|
||||
}
|
||||
},
|
||||
"deadWaitTime": 0,
|
||||
"normalWaitTime": 0,
|
||||
"retryWaitTime": 10000,
|
||||
"sleepWaitTime": 3600000,
|
||||
"comaWaitTime": 86400000,
|
||||
"statusDependencies": [
|
||||
{
|
||||
"dataMine": "AAMasters",
|
||||
"bot": "AACharly",
|
||||
"botVersion": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
},
|
||||
"process": "Historic-Trades",
|
||||
"dataSetVersion": "dataSet.V1"
|
||||
},
|
||||
{
|
||||
"dataMine": "AAMasters",
|
||||
"bot": "AACharly",
|
||||
"botVersion": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
},
|
||||
"process": "Hole-Fixing",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSetSection": "Month",
|
||||
"waitUntilNextUpdate": true
|
||||
},
|
||||
{
|
||||
"dataMine": "AAMasters",
|
||||
"bot": "AABruce",
|
||||
"botVersion": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
},
|
||||
"process": "Single-Period-Daily",
|
||||
"dataSetVersion": "dataSet.V1",
|
||||
"dataSetSection": "Month"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"products": [
|
||||
{
|
||||
"codeName": "Candles",
|
||||
"displayName": "Candles",
|
||||
"description": "01 Min Candles.",
|
||||
"storageAccount": "aamasters",
|
||||
"dataSets": [
|
||||
{
|
||||
"codeName": "One-Min",
|
||||
"type": "Daily Files",
|
||||
"validPeriods": [ "01-min" ],
|
||||
"filePath": "AAMasters/AAOlivia.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Candles/One-Min",
|
||||
"fileName": "Data.json"
|
||||
}
|
||||
],
|
||||
"exchangeList": [
|
||||
{
|
||||
"name": "Poloniex"
|
||||
},
|
||||
{
|
||||
"name": "Coss"
|
||||
}
|
||||
],
|
||||
"plotter": {
|
||||
"dataMine": "AAMasters",
|
||||
"codeName": "PlottersCandlesVolumes",
|
||||
"moduleName": "Candles"
|
||||
}
|
||||
},
|
||||
{
|
||||
"codeName": "Volumes",
|
||||
"displayName": "Buy and Sell Volumes",
|
||||
"description": "01 Min Volumes.",
|
||||
"storageAccount": "aamasters",
|
||||
"dataSets": [
|
||||
{
|
||||
"codeName": "One-Min",
|
||||
"type": "Daily Files",
|
||||
"validPeriods": [ "01-min" ],
|
||||
"filePath": "AAMasters/AAOlivia.1.0/AACloud.1.1/@Exchange/dataSet.V1/Output/Volumes/One-Min",
|
||||
"fileName": "Data.json"
|
||||
}
|
||||
],
|
||||
"exchangeList": [
|
||||
{
|
||||
"name": "Poloniex"
|
||||
},
|
||||
{
|
||||
"name": "Coss"
|
||||
}
|
||||
],
|
||||
"plotter": {
|
||||
"dataMine": "AAMasters",
|
||||
"codeName": "PlottersCandlesVolumes",
|
||||
"moduleName": "Volumes"
|
||||
}
|
||||
}
|
||||
],
|
||||
"storage": {
|
||||
"sas": "?sv=2017-07-29&ss=b&srt=sco&sp=rl&se=2018-12-31T22:59:59Z&st=2018-04-01T12:59:54Z&spr=https&sig=Fre%2FUWrF9IAXNnJSOZ%2F5q5LUow9uno7dXg5pGZ3YDzo%3D",
|
||||
"fileUri": "https://aamasters.blob.core.windows.net"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user