From 784e39e9717730996eaa03ff6173fe89f122385c Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Wed, 20 Feb 2019 09:25:41 +0100 Subject: [PATCH] Market Files generated successfully --- Multi-Period-Market/User.Bot.js | 203 +++++++++++--------------------- Tom.png | Bin 16438 -> 0 bytes this.bot.config.json | 16 +-- 3 files changed, 74 insertions(+), 145 deletions(-) delete mode 100644 Tom.png diff --git a/Multi-Period-Market/User.Bot.js b/Multi-Period-Market/User.Bot.js index 547e93984..8725317f9 100644 --- a/Multi-Period-Market/User.Bot.js +++ b/Multi-Period-Market/User.Bot.js @@ -10,7 +10,7 @@ const TRADES_FOLDER_NAME = "Trades"; const CANDLES_FOLDER_NAME = "Candles"; - const BOLINGER_BANDS_FOLDER_NAME = "Boliniger-Bands"; + const BOLINGER_BANDS_FOLDER_NAME = "Bollinger-Bands"; const commons = COMMONS.newCommons(bot, logger, UTILITIES); @@ -64,7 +64,7 @@ This process is going to do the following: - Read the candles and volumes from Olivia and produce the bollinger bands out of them. + Read the candles from Olivia and produce the bollinger bands out of them. */ @@ -76,11 +76,11 @@ let market = global.MARKET; - buildStairs(); + buildBands(); - function buildStairs() { + function buildBands() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> Entering function."); } try { @@ -92,7 +92,7 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> periodsLoop -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> periodsLoop -> Entering function."); } /* @@ -106,7 +106,7 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> periodsLoop -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> periodsLoop -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -115,7 +115,7 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> loopBody -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> Entering function."); } const outputPeriod = global.marketFilesPeriods[n][0]; const timePeriod = global.marketFilesPeriods[n][1]; @@ -126,7 +126,7 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> loopBody -> nextCandleFile -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> Entering function."); } let fileName = market.assetA + '_' + market.assetB + ".json"; @@ -139,12 +139,12 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> text = " + text); } + 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 -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.message); callBackFunction(err); return; @@ -153,13 +153,13 @@ let marketFile = JSON.parse(text); let candles = []; - let stairsArray = []; + let bandsArray = []; buildCandles(); function buildCandles() { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> buildCandles -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> buildCandles -> Entering function."); } try { @@ -184,156 +184,85 @@ candle.begin = marketFile[i][4]; candle.end = marketFile[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); } - findCandleStairs(); + buildBands(); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> buildCandles -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> buildCandles -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function findCandleStairs() { + function buildBands() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> findCandleStairs -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> buildBands -> Entering function."); } - /* Finding stairs */ + let n = 20; - let stairs; + /* Building bands */ - for (let i = 0; i < candles.length - 1; i++) { + let band; - let currentCandle = candles[i]; - let nextCandle = candles[i + 1]; + for (let i = n - 1; i < candles.length - 1; i++) { // Go through all the candles to generate a band segment for each of them. - if (currentCandle.direction === nextCandle.direction && currentCandle.direction !== 'side') { - - if (stairs === undefined) { - - stairs = { - open: undefined, - close: undefined, - min: 10000000000000, - max: 0, - begin: undefined, - end: undefined, - direction: undefined, - candleCount: 0, - firstMin: 0, - firstMax: 0, - lastMin: 0, - lastMax: 0 - }; - - stairs.direction = currentCandle.direction; - stairs.candleCount = 2; - - stairs.begin = currentCandle.begin; - stairs.end = nextCandle.end; - - stairs.open = currentCandle.open; - stairs.close = nextCandle.close; - - if (currentCandle.min < nextCandle.min) { stairs.min = currentCandle.min; } else { stairs.min = nextCandle.min; } - if (currentCandle.max > nextCandle.max) { stairs.max = currentCandle.max; } else { stairs.max = nextCandle.max; } - - if (stairs.direction === 'up') { - - stairs.firstMin = currentCandle.open; - stairs.firstMax = currentCandle.close; - - stairs.lastMin = nextCandle.open; - stairs.lastMax = nextCandle.close; - - } else { - - stairs.firstMin = currentCandle.close; - stairs.firstMax = currentCandle.open; - - stairs.lastMin = nextCandle.close; - stairs.lastMax = nextCandle.open; - - } - - - } else { - - stairs.candleCount++; - stairs.end = nextCandle.end; - stairs.close = nextCandle.close; - - if (stairs.min < nextCandle.min) { stairs.min = currentCandle.min; } - if (stairs.max > nextCandle.max) { stairs.max = currentCandle.max; } - - if (stairs.direction === 'up') { - - stairs.lastMin = nextCandle.open; - stairs.lastMax = nextCandle.close; - - } else { - - stairs.lastMin = nextCandle.close; - stairs.lastMax = nextCandle.open; - - } - - } - - } else { - - if (stairs !== undefined) { - stairsArray.push(stairs); - stairs = undefined; - } + let movingAverage = 0; + for (let j = i - n + 1; j < i + 1; j++) { // go through the last n candles to calculate the moving average. + movingAverage = movingAverage + candles[j].close; } + movingAverage = movingAverage / n; + + let standardDeviation = 0; + for (let j = i - n + 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 / n; + standardDeviation = Math.sqrt(standardDeviation); + + band = { + begin: candles[i].begin, + end: candles[i].end, + movingAverage: movingAverage, + standardDeviation: standardDeviation + }; + + bandsArray.push(band); + } - writeCandleStairsFile(); + writeBandsFile(); } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> findCandleStairs -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> buildBands -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } - function writeCandleStairsFile() { + function writeBandsFile() { try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> writeCandleStairsFile -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> Entering function."); } let separator = ""; let fileRecordCounter = 0; let fileContent = ""; - for (i = 0; i < stairsArray.length; i++) { + for (i = 0; i < bandsArray.length; i++) { - let stairs = stairsArray[i]; + let band = bandsArray[i]; fileContent = fileContent + separator + '[' + - stairs.open + "," + - stairs.close + "," + - stairs.min + "," + - stairs.max + "," + - stairs.begin + "," + - stairs.end + "," + - '"' + stairs.direction + '"' + "," + - stairs.candleCount + "," + - stairs.firstMin + "," + - stairs.firstMax + "," + - stairs.lastMin + "," + - stairs.lastMax + "]"; + band.begin + "," + + band.end + "," + + band.movingAverage + "," + + band.standardDeviation + "]"; if (separator === "") { separator = ","; } @@ -354,14 +283,14 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> writeCandleStairsFile -> onFileCreated -> Entering function."); } - if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> writeCandleStairsFile -> onFileCreated -> fileContent = " + fileContent); } + 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 -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> writeCandleStairsFile -> onFileCreated -> err = " + err.message); - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> writeCandleStairsFile -> onFileCreated -> filePath = " + filePath); - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> writeCandleStairsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> err = " + err.message); + 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.assetA + "_" + market.assetB); callBackFunction(err); return; @@ -372,32 +301,32 @@ } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> writeCandleStairsFile -> onFileCreated -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> onFileCreated -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> writeCandleStairsFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> writeBandsFile -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> onFileReceived -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> loopBody -> nextCandleFile -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> nextCandleFile -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> loopBody -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> loopBody -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } @@ -406,7 +335,7 @@ try { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildStairs -> controlLoop -> Entering function."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildBands -> controlLoop -> Entering function."); } n++; @@ -421,14 +350,14 @@ } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> controlLoop -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> controlLoop -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } } catch (err) { - logger.write(MODULE_NAME, "[ERROR] start -> buildStairs -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] start -> buildBands -> err = " + err.message); callBackFunction(global.DEFAULT_FAIL_RESPONSE); } } diff --git a/Tom.png b/Tom.png deleted file mode 100644 index dfd3561738ce327a580b093e53e93a9ccc0f38c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16438 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 a*uvEPKMRCZ$^iZe07;6