Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- "use strict";
- exports.__esModule = true;
- var renderchart_1 = require("./renderchart");
- var request = require('request');
- var candlestick_1 = require("./candlestick");
- var telegram = require('telegram-bot-api');
- //const player = require('play-sound')();
- var fs = require('fs');
- var slack_1 = require("./slack");
- var masterCurrencies = ['USD', 'USDT', 'EUR', 'BTC', 'ETH']; //'XMR'
- var slackCurrencyGroup = { 'BTC': 'BTC', 'ETH': 'ETH', 'USD': 'Fiat', 'EUR': 'Fiat', 'USDT': 'Fiat' };
- var slackThreadCurrency = { 'BTC': 'BTC', 'ETH': 'ETH', 'USD': 'USD', 'EUR': 'EUR', 'USDT': 'USD' };
- var CurrencyPair = /** @class */ (function () {
- function CurrencyPair(primary_curr, base_curr, exchange) {
- this.primary_curr = primary_curr;
- this.base_curr = base_curr;
- this.exchange = exchange;
- // Array of minute candlesticks for last two hours
- this.candles_1m = new Array();
- // Array of hour candlesticks for last two months
- this.candles_1h = new Array();
- // Remember if last ticker triggered an alert with the same base time, prevent duplicate alerts
- this.lastDropState = false;
- this.lastLowerTime = 0;
- this.lastBaseCandle = null;
- // Time when a base was last found. Ignore newer bases for <ignorenewer> hours.
- this.lastBaseFoundTime = 0;
- // Holds master and secondary currencies: { curr1: master, curr2: secondary }
- this.masterCurrency = null;
- // Holds the name of the slack group
- this.slackGroup = null;
- // Slack thread id
- this.threadId = null;
- // Ignore this currency pair, use for delisted pairs etc.
- this.ignore = false;
- this.lastCurrentLow = 0;
- // Check if an least one of the currencies is a "master currency"
- this.masterCurrency = this.FindMasterCurrency(primary_curr, base_curr);
- // If the currency pair contains a master currency, find the correct slack group and read the settings
- if (this.masterCurrency) {
- this.slackGroup = ('scanner_alerts_' + slackCurrencyGroup[this.masterCurrency.curr1]).toLowerCase();
- this.ReadSettings();
- }
- }
- // Find out if the currency pair contains at least one master currency, and order the currencies so the strongest one comes first
- CurrencyPair.prototype.FindMasterCurrency = function (curr1, curr2) {
- var curr1index = masterCurrencies.indexOf(curr1);
- var curr2index = masterCurrencies.indexOf(curr2);
- if (curr1index < 0)
- curr1index = 999; // Not a master currency
- if (curr2index < 0)
- curr2index = 999; // Not a master currency
- if (curr1index == 999 && curr2index == 999) {
- console.log(curr1 + '/' + curr2 + ' No master currency');
- return null;
- }
- else if (curr1index < curr2index) {
- return { curr1: curr1, curr2: curr2 };
- }
- else {
- return { curr1: curr2, curr2: curr1 };
- }
- };
- // Read settings for this currency pair. The settings are the slack thread id and whether to ignore the currency pair (in case of delisting etc)
- CurrencyPair.prototype.ReadSettings = function () {
- var settingsFile = './data/' + slackThreadCurrency[this.masterCurrency.curr1] + '_' + this.masterCurrency.curr2 + '.settings.json';
- if (this.FileExists(settingsFile)) {
- var settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
- if (settings.threadId)
- this.threadId = settings.threadId;
- if (settings.ignore)
- this.ignore = settings.ignore;
- }
- };
- // Select if the currency pair should be ignored (never alert)
- CurrencyPair.prototype.SetIgnore = function (value) {
- this.ignore = value;
- this.WriteSettings();
- if (value)
- console.log('Ignoring ' + this.exchange.exch_code + ' ' + this.base_curr + ' ' + this.primary_curr);
- else
- console.log('No longer ignoring ' + this.exchange.exch_code + ' ' + this.base_curr + ' ' + this.primary_curr);
- };
- // Write settings to file
- CurrencyPair.prototype.WriteSettings = function () {
- var settingsFile = './data/' + slackThreadCurrency[this.masterCurrency.curr1] + '_' + this.masterCurrency.curr2 + '.settings.json';
- var settings = { threadId: this.threadId, ignore: this.ignore };
- fs.writeFileSync(settingsFile, JSON.stringify(settings), 'utf8');
- };
- // Check if a file exists
- CurrencyPair.prototype.FileExists = function (filePath) {
- try {
- fs.statSync(filePath);
- }
- catch (err) {
- if (err.code == 'ENOENT')
- return false;
- }
- return true;
- };
- // Get history from Coinigy
- CurrencyPair.prototype.GetHistory = function (callback) {
- var _this = this;
- var historyfile = './data/' + this.exchange.exch_code + '_' + this.base_curr + '_' + this.primary_curr + '.json';
- // Calculate current unix timestamp
- var unixtime = Math.round(+new Date() / 1000);
- // Unix timestamp one hour ago. Will get minute candles for last hour.
- var fromtime_1m = unixtime - 3600;
- // Unix timestamp 60 days ago. Will get hour candlesticks for last two months.
- var fromtime_1h = unixtime - 3600 * CurrencyPair.max1hcandles;
- // Url for minute candles for desired time range
- var url1m = "https://www.coinigy.com/getjson/chart_feed/" + this.exchange.exch_code + "/" + this.primary_curr + "/" + this.base_curr + "/1/" + fromtime_1m + "/" + unixtime;
- // Get minute candles from coinigy
- request(url1m, function (err, res, body) {
- if (!err && res.statusCode == 200) {
- JSON.parse(body).forEach(function (x) {
- var c = new candlestick_1.CandleStick();
- c.start_time = x[0];
- c.open = x[1];
- c.high = x[2];
- c.low = x[3];
- c.close = x[4];
- _this.candles_1m.push(c);
- });
- // Read history from JSON file, if exists
- if (_this.FileExists(historyfile)) {
- var history_1 = JSON.parse(fs.readFileSync(historyfile, 'utf8')).filter(function (x) { return x.start_time > fromtime_1h; });
- history_1.forEach(function (x) {
- var c = new candlestick_1.CandleStick();
- c.start_time = x.start_time;
- c.close = x.close;
- c.high = x.high;
- c.low = x.low;
- c.open = x.open;
- _this.candles_1h.push(c);
- });
- if (_this.candles_1h.length > 0)
- _this.candles_1h.shift();
- if (_this.candles_1h.length > 0)
- fromtime_1h = _this.candles_1h[0].start_time + 3600;
- }
- // Url for 1 hour candles
- var url1h = "https://www.coinigy.com/getjson/chart_feed/" + _this.exchange.exch_code + "/" + _this.primary_curr + "/" + _this.base_curr + "/60/" + fromtime_1h + "/" + unixtime;
- // Get (newer) hour candles from coinigy
- request(url1h, function (err, res, body) {
- if (!err && res.statusCode == 200) {
- var newCandles_1 = new Array();
- JSON.parse(body).forEach(function (x) {
- var c = new candlestick_1.CandleStick();
- c.start_time = x[0];
- c.open = x[1];
- c.high = x[2];
- c.low = x[3];
- c.close = x[4];
- newCandles_1.push(c);
- });
- _this.candles_1h = newCandles_1.concat(_this.candles_1h);
- // Write history to JSON file
- fs.writeFileSync(historyfile, JSON.stringify(_this.candles_1h), 'utf8');
- // Finished getting history for this coin
- callback();
- }
- else {
- // Error getting 1 hour candles
- console.log(err);
- }
- });
- }
- else {
- // Error getting 1 minute candles
- console.log(err);
- }
- });
- };
- // Get Coinigy url for this currency pair
- CurrencyPair.prototype.GetCoinigyUrl = function () {
- return "https://www.coinigy.com/main/markets/" + this.exchange.exch_code + "/" + this.primary_curr + "/" + this.base_curr;
- };
- // Find the first base, don't look for bases for the last <ignoreHours> hours
- CurrencyPair.prototype.FindBase = function (value, ignoreHours) {
- // First candle found with low value lower than <maxbottomdistance> above <value>
- var firstCandle = null;
- // Lowest candle body found
- var lowestCandle = null;
- // Current candle number, 0 is newest
- var i = 0;
- // Discovery state. 0: Looking for candle with low value < maxbottomdistance. 1: Looking for bottom of base
- var state = 0;
- // Number of consecutive candles with body low > lowest candle body low
- var skippedCandles = 0;
- // Iterate through the hourly candles back in time
- for (var _i = 0, _a = this.candles_1h; _i < _a.length; _i++) {
- var x = _a[_i];
- // For the first candles, only check if they are higher than the current price, not if they are bases. If a candle is lower that the current price, stop looking.
- if (i < ignoreHours) {
- if (value > x.low) {
- lowestCandle = x;
- break;
- }
- } // State 0 - look for a candle that is < maxbottomdistance above current price.
- else if (state == 0 && x.bodylow() <= (value * (1 + CurrencyPair.maxbottomdistance / 100)) && i >= ignoreHours) {
- firstCandle = x;
- lowestCandle = firstCandle;
- state = 1;
- }
- else if (state == 1) {
- if (x.bodylow() <= firstCandle.bodylow()) {
- if (x.bodylow() < lowestCandle.bodylow()) {
- lowestCandle = x;
- }
- skippedCandles = 0;
- }
- else {
- skippedCandles++;
- if (skippedCandles > CurrencyPair.maxskipcandles) {
- break;
- }
- }
- }
- i++;
- }
- return lowestCandle;
- };
- // Find the lowest price in a given period, looks a little buggy
- CurrencyPair.prototype.GetLow = function (start_time, end_time) {
- var low = -1;
- var last_candle_start = Math.floor(end_time / 3600) * 3600;
- this.candles_1h.filter(function (x) { return x.start_time >= start_time && x.start_time < last_candle_start; }).forEach(function (y) {
- if (low > 0 || y.low < low)
- low = y.low;
- });
- var lastCandle = this.GetCandleForTime(last_candle_start, end_time); // Calculate the last 1h candle from 1m candles. Only applicable if end_time is within the last hour.
- if (lastCandle && (lastCandle.low < low || low < 0))
- low = lastCandle.low;
- return low;
- };
- // Calculate a candle between to timestamps from 1m candles
- CurrencyPair.prototype.GetCandleForTime = function (start_time, end_time) {
- if (this.candles_1m.length == 0)
- return null;
- var cs1h = new candlestick_1.CandleStick();
- cs1h.close = this.candles_1m[0].close;
- cs1h.high = this.candles_1m[0].high;
- cs1h.low = this.candles_1m[0].low;
- cs1h.open = this.candles_1m[0].open;
- cs1h.start_time = start_time;
- var c_1m = this.candles_1m.filter(function (x) { return x.start_time >= cs1h.start_time && x.start_time < end_time; });
- c_1m.forEach(function (y) {
- cs1h.open = y.open;
- cs1h.high = Math.max(cs1h.high, y.high);
- cs1h.low = Math.min(cs1h.low, y.low);
- });
- return cs1h;
- };
- // New tick received from exchange, perform calculations
- CurrencyPair.prototype.NewTick = function (ticker) {
- // Cancel if currency pair is set to be ignored.
- if (this.ignore)
- return;
- var unix = ticker.tick_time;
- this.base_volume = ticker.base_volume_24;
- this.primary_volume = ticker.primary_volume_24;
- // Add a new candle to the 1h array if a new hour has started or this is the first tick received
- if (!this.last_tick_time || Math.floor(unix / 3600) != Math.floor(this.last_tick_time / 3600)) {
- var cs = this.GetCandleForTime(Math.floor(unix / 3600) * 3600, unix);
- if (!cs)
- cs = new candlestick_1.CandleStick();
- cs.open = ticker.last_price;
- cs.high = ticker.last_price;
- cs.low = ticker.last_price;
- cs.start_time = Math.floor(unix / 3600) * 3600; // Calculate exact start time of this hour
- this.candles_1h.unshift(cs);
- this.candles_1h = this.candles_1h.filter(function (x) { return x.start_time > unix - 3600 * 24 * 60; }); // Remove candles more than 60 days old
- }
- // Add a new candle to the 1m array if a new minute has started or this is the first tick received
- if (!this.last_tick_time || Math.floor(unix / 60) != Math.floor(this.last_tick_time / 60)) {
- var cs = new candlestick_1.CandleStick();
- cs.open = ticker.last_price;
- cs.high = ticker.last_price;
- cs.low = ticker.last_price;
- cs.start_time = Math.floor(unix / 60) * 60; // Calculate exact start time of this minute
- this.candles_1m.unshift(cs);
- this.candles_1m = this.candles_1m.filter(function (x) { return x.start_time > unix - 3600; }); // Remove candles more than 1h old
- this.lastCurrentLow = 0;
- }
- // If the 1h array contains at least one candle, update high, low and close-prices
- if (this.candles_1h.length > 0 && this.candles_1h[0]) {
- this.candles_1h[0].high = Math.max(this.candles_1h[0].high, ticker.last_price);
- this.candles_1h[0].low = Math.min(this.candles_1h[0].low, ticker.last_price);
- this.candles_1h[0].close = ticker.last_price;
- }
- else {
- console.log("1h candle missing in " + this.exchange + ": " + this.base_curr + "-" + this.primary_curr);
- }
- // If the 1m array contains at least one candle, update high, low and close-prices
- if (this.candles_1m.length > 0 && this.candles_1m[0]) {
- this.candles_1m[0].high = Math.max(this.candles_1m[0].high, ticker.last_price);
- this.candles_1m[0].low = Math.min(this.candles_1m[0].low, ticker.last_price);
- this.candles_1m[0].close = ticker.last_price;
- }
- else {
- console.log("1m candle missing in " + this.exchange + ": " + this.base_curr + "-" + this.primary_curr);
- }
- this.last_tick_time = unix;
- // Check if price has dropped below a base
- this.CheckDrop();
- };
- ;
- // Used when running the scanner locally, to give a sound when an alert is issued
- CurrencyPair.prototype.PlaySound = function () {
- /* player.play('./ting.mp3', (err) => {
- if (err) console.log(`Could not play sound: ${err}`);
- });*/
- };
- // Create a graph using techan charts
- CurrencyPair.prototype.CreateGraphic = function (fromCandle, baseCandle, base, title, message, value) {
- var _this = this;
- var r = new renderchart_1.RenderChart();
- var basestart = Math.min(this.candles_1h.length - 1, baseCandle);
- var baseend = 0;
- // Create a unique filename for the chart
- var filename = this.exchange.exch_code + " " + this.base_curr + "_" + this.primary_curr + " " + +new Date() + ".png";
- console.log('Rendering...');
- r.render(this.candles_1h.slice(0, fromCandle), value, { FromTime: new Date(this.candles_1h[baseend].start_time * 1000), ToTime: new Date(this.candles_1h[basestart].start_time * 1000), Level: base }, filename, this.exchange.exch_code + " " + this.base_curr + "_" + this.primary_curr, function (file) {
- console.log('Render complete');
- var url = 'http://quickfingers.trade/alerts/' + file;
- console.log(message);
- });
- // If slack is enabled and there is a group for this pair, send an alert
- /*if (CurrencyPair.useSlack && this.slackGroup) {
- console.log('Rendering...');
- r.render(this.candles_1h.slice(0, fromCandle), value, { FromTime: new Date(this.candles_1h[baseend].start_time * 1000), ToTime: new Date(this.candles_1h[basestart].start_time * 1000), Level: base }, filename, this.exchange.exch_code + " " + this.base_curr + "_" + this.primary_curr, function (file) {
- console.log('Render complete, sending slack message');
- var url = 'http://quickfingers.trade/alerts/' + file;
- CurrencyPair.slack.send(_this.slackGroup, url, title, message, _this.threadId, function (ts) {
- // If a new thread was created, save the thread id
- if (_this.threadId != ts) {
- _this.threadId = ts;
- _this.WriteSettings();
- }
- });
- });
- }*/
- };
- // Check if the price has dropped below the base
- CurrencyPair.prototype.CheckDrop = function () {
- // Only check if there is at least one 1m candle, should always be true
- if (this.candles_1m.length > 0) {
- // Find the low value of the current candle, only check if the price is different from last time
- var currentLow = this.candles_1m[0].low;
- if (currentLow != this.lastCurrentLow) {
- this.lastCurrentLow = currentLow;
- var unix = Math.round(+new Date() / 1000);
- // Find the closest base
- var baseCandle = this.FindBase(currentLow, CurrencyPair.ignorehours);
- if (baseCandle) {
- // Continue if there wasn't found a base candle last time, if this base is older than the last one found or if it's more than <ignoreNewer> hours since the last base was found
- if (!this.lastBaseCandle || baseCandle.start_time < this.lastBaseCandle.start_time || (unix - this.lastBaseFoundTime) > CurrencyPair.ignoreNewer * 3600) {
- var timeSinceLastLow = Math.floor((unix - baseCandle.start_time) / 3600);
- // Alert if the base is at least <minddrop> % above current price, at least <minhours> hours old and isn't the same base that was alerted last time
- if ((baseCandle.bodylow() > currentLow * (1 + CurrencyPair.mindrop / 100)) && timeSinceLastLow > CurrencyPair.minhours && baseCandle.start_time != this.lastLowerTime) {
- var title = "(" + this.exchange.exch_code + ") " + this.primary_curr + "/" + this.base_curr;
- var message = "Last base: " + timeSinceLastLow + "h ago\nVolume: " + Math.round(this.base_volume * 100) / 100 + " " + this.base_curr + " / " + Math.round(this.primary_volume * 100) / 100 + " " + this.primary_curr + "\nPrice: " + this.candles_1m[0].close + "\n" + this.GetCoinigyUrl() + "\n" + this.exchange.GetUrl(this.primary_curr, this.base_curr);
- this.lastLowerTime = baseCandle.start_time;
- this.lastBaseCandle = baseCandle;
- this.lastBaseFoundTime = unix;
- this.PlaySound();
- // Create the graph and send to slack
- this.CreateGraphic(this.candles_1h.length - 24, this.candles_1h.indexOf(baseCandle), baseCandle.bodylow(), title, message, currentLow);
- }
- }
- }
- else if (this.candles_1h.length > CurrencyPair.minhours) {
- if (this.lastLowerTime != -999) {
- var title = "(" + this.exchange.exch_code + ") " + this.primary_curr + "/" + this.base_curr;
- var message = "Lowest value in > " + this.candles_1h.length + "h\n" +
- "Volume: " + Math.round(this.base_volume * 100) / 100 + " " + this.base_curr + " / " + Math.round(this.primary_volume * 100) / 100 + " " + this.primary_curr + "\nPrice: " + this.candles_1m[0].close +
- '\n' + this.GetCoinigyUrl() + '\n' + this.exchange.GetUrl(this.primary_curr, this.base_curr);
- this.lastLowerTime = -999;
- this.PlaySound();
- // Create the graph and send to slack
- this.CreateGraphic(this.candles_1h.length - 24, 0, -1, title, message, currentLow);
- }
- } // Alert once if there are no 1h candles
- else if (this.candles_1h.length == 0) {
- if (this.lastLowerTime != -998)
- console.log("No 1h candles for: (" + this.exchange.exch_code + ") " + this.primary_curr + "/" + this.base_curr);
- this.lastLowerTime = -998;
- }
- }
- }
- };
- CurrencyPair.slack = new slack_1.Slack();
- // Maximum number of 1h candles to keep
- CurrencyPair.max1hcandles = 24 * 60;
- // Settings
- // Minimum drop from base before alerting
- CurrencyPair.mindrop = 5;
- // Maximum distance to candle when searching for bases
- CurrencyPair.maxbottomdistance = 8;
- // Minimum time since last base
- CurrencyPair.minhours = 72;
- // Ignore last x hours when searching for a base
- CurrencyPair.ignorehours = 12;
- // Maximum candles with higher body than the first candle found on the current base. Used when searching for bottom of base
- CurrencyPair.maxskipcandles = 8;
- // Send to telegram channel
- CurrencyPair.useSlack = false;
- // Number of hours to ignore newer bases than the last one that was found
- CurrencyPair.ignoreNewer = 2;
- return CurrencyPair;
- }());
- exports.CurrencyPair = CurrencyPair;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement