├── .gitattributes ├── chart.png ├── .gitignore ├── README.md ├── package.json ├── LICENSE └── bot_TokenPricePrediction.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glory413/Bot_TokenPricePrediction/HEAD/chart.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Environment variables 2 | .env 3 | 4 | #Node.js 5 | package-lock.json 6 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | This is a bot that predict token price. 3 | 4 | ### Running the bot 5 | First, we need to install the dependencies in order for the bot to run correctly. From the root, just execute the following command. 6 | ``` 7 | npm install 8 | ``` 9 | That's it, we're ready to run the bot, just use this script: 10 | ``` 11 | npm run start 12 | ``` 13 | And that's all, you can now interact with your bot using Telegram. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "start": "node bot_TokenPricePrediction.js" 5 | }, 6 | "dependencies": { 7 | "axios": "^1.3.2", 8 | "chart.js-image": "^6.1.3", 9 | "chat.js": "^1.0.2", 10 | "dotenv": "^16.0.3", 11 | "ethereum-block-by-date": "^1.4.6", 12 | "fs": "^0.0.1-security", 13 | "node-telegram-bot-api": "^0.59.0", 14 | "openai": "^3.1.0", 15 | "plotly": "^1.0.6", 16 | "web3": "^1.8.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Javi Toro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bot_TokenPricePrediction.js: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'module' 2 | const require = createRequire(import.meta.url) 3 | const Web3 = require("web3"); 4 | const axios = require("axios"); 5 | const EthDater = require('ethereum-block-by-date'); 6 | const ChartJSImage = require('chart.js-image'); 7 | const fs = require('fs'); 8 | const TelegramBot = require('node-telegram-bot-api') 9 | const dotenv = require('dotenv') 10 | 11 | dotenv.config() 12 | 13 | const token = process.env.TELEGRAM_BOT_TOKEN 14 | const bot = new TelegramBot(token, { polling: true }) 15 | 16 | const web3 = new Web3("https://ethereum.publicnode.com"); 17 | const dater = new EthDater( 18 | web3 // Web3 object, required. 19 | ); 20 | const filePath = './chart.png'; 21 | let TOKEN_ADDRESS = ''; 22 | 23 | const tokenMap = new Map() 24 | tokenMap.set("ETH", "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2") 25 | tokenMap.set("eth", "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2") 26 | tokenMap.set("WETH", "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2") 27 | tokenMap.set("weth", "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2") 28 | tokenMap.set("WBTC", "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599") 29 | tokenMap.set("wbtc", "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599") 30 | tokenMap.set("USDC", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48") 31 | tokenMap.set("usdc", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48") 32 | tokenMap.set("LINK", "0x514910771AF9Ca656af840dff83E8264EcF986CA") 33 | tokenMap.set("link", "0x514910771AF9Ca656af840dff83E8264EcF986CA") 34 | tokenMap.set("UNI", "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984") 35 | tokenMap.set("uni", "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984") 36 | tokenMap.set("ENS", "0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72") 37 | tokenMap.set("ens", "0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72") 38 | tokenMap.set("DAI", "0x6B175474E89094C44Da98b954EedeAC495271d0F") 39 | tokenMap.set("dai", "0x6B175474E89094C44Da98b954EedeAC495271d0F") 40 | tokenMap.set("MATIC", "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0") 41 | tokenMap.set("matic", "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0") 42 | tokenMap.set("NOSTRA", "0xA813Ac8E0DB2c9Ec28d2b2725461A5765f366eEB") 43 | tokenMap.set("nostra", "0xA813Ac8E0DB2c9Ec28d2b2725461A5765f366eEB") 44 | 45 | bot.onText(/\/p (.+)/, async (msg, match) => { 46 | const chatId = msg.chat.id 47 | if (match[1].includes("0x")) { 48 | TOKEN_ADDRESS = match[1]; 49 | } 50 | else if (tokenMap.has(match[1])) 51 | { 52 | TOKEN_ADDRESS = tokenMap.get(match[1]); 53 | } 54 | else { 55 | bot.sendMessage(chatId, "The string is not Token Address or Token Name."); 56 | return; 57 | } 58 | 59 | const url = "https://api.dexscreener.com/latest/dex/tokens/" + TOKEN_ADDRESS; 60 | let event_data_res = await fetch(url); 61 | let event_data = await event_data_res.json(); 62 | let i = 0; 63 | 64 | let vVolume = 0; 65 | let vLiquidity = 0; 66 | let vTotalSupply = 0; 67 | 68 | if(event_data.pairs == null) 69 | { 70 | return; 71 | } 72 | 73 | for(i=0;i { 107 | let blocknumbers = []; 108 | for(let idx = 0; idx < blockRecords.length; idx ++) 109 | { 110 | blocknumbers.push(blockRecords[idx].block); 111 | } 112 | 113 | let fetchingPricesPromise = []; 114 | 115 | fetchingPricesPromise.push( 116 | axios.get(`https://deep-index.moralis.io/api/v2/erc20/${TOKEN_ADDRESS}/price`, { 117 | headers: { 118 | "x-api-key": "uyKibkyh4ljytsSBlA0VYcpsPH6ji8CXjqSZDm70J4gsiJuvaTnt1WkwAp9fH5L3" 119 | }, 120 | params: { 121 | chain: "eth", 122 | exchange: "uniswap-v2", 123 | to_block: blocknumbers[0] 124 | } 125 | }) 126 | ); 127 | 128 | fetchingPricesPromise.push( 129 | axios.get(`https://deep-index.moralis.io/api/v2/erc20/${TOKEN_ADDRESS}/price`, { 130 | headers: { 131 | "x-api-key": "uyKibkyh4ljytsSBlA0VYcpsPH6ji8CXjqSZDm70J4gsiJuvaTnt1WkwAp9fH5L3" 132 | }, 133 | params: { 134 | chain: "eth", 135 | exchange: "uniswap-v2", 136 | to_block: blocknumbers[1] 137 | } 138 | }) 139 | ); 140 | 141 | fetchingPricesPromise.push( 142 | axios.get(`https://deep-index.moralis.io/api/v2/erc20/${TOKEN_ADDRESS}/price`, { 143 | headers: { 144 | "x-api-key": "uyKibkyh4ljytsSBlA0VYcpsPH6ji8CXjqSZDm70J4gsiJuvaTnt1WkwAp9fH5L3" 145 | }, 146 | params: { 147 | chain: "eth", 148 | exchange: "uniswap-v2", 149 | to_block: blocknumbers[2] 150 | } 151 | }) 152 | ); 153 | 154 | fetchingPricesPromise.push( 155 | axios.get(`https://deep-index.moralis.io/api/v2/erc20/${TOKEN_ADDRESS}/price`, { 156 | headers: { 157 | "x-api-key": "uyKibkyh4ljytsSBlA0VYcpsPH6ji8CXjqSZDm70J4gsiJuvaTnt1WkwAp9fH5L3" 158 | }, 159 | params: { 160 | chain: "eth", 161 | exchange: "uniswap-v2", 162 | to_block: blocknumbers[3] 163 | } 164 | }) 165 | ); 166 | 167 | fetchingPricesPromise.push( 168 | axios.get(`https://deep-index.moralis.io/api/v2/erc20/${TOKEN_ADDRESS}/price`, { 169 | headers: { 170 | "x-api-key": "uyKibkyh4ljytsSBlA0VYcpsPH6ji8CXjqSZDm70J4gsiJuvaTnt1WkwAp9fH5L3" 171 | }, 172 | params: { 173 | chain: "eth", 174 | exchange: "uniswap-v2", 175 | to_block: blocknumbers[4] 176 | } 177 | }) 178 | ); 179 | 180 | fetchingPricesPromise.push( 181 | axios.get(`https://deep-index.moralis.io/api/v2/erc20/${TOKEN_ADDRESS}/price`, { 182 | headers: { 183 | "x-api-key": "uyKibkyh4ljytsSBlA0VYcpsPH6ji8CXjqSZDm70J4gsiJuvaTnt1WkwAp9fH5L3" 184 | }, 185 | params: { 186 | chain: "eth", 187 | exchange: "uniswap-v2", 188 | to_block: blocknumbers[5] 189 | } 190 | }) 191 | ); 192 | 193 | fetchingPricesPromise.push( 194 | axios.get(`https://deep-index.moralis.io/api/v2/erc20/${TOKEN_ADDRESS}/price`, { 195 | headers: { 196 | "x-api-key": "uyKibkyh4ljytsSBlA0VYcpsPH6ji8CXjqSZDm70J4gsiJuvaTnt1WkwAp9fH5L3" 197 | }, 198 | params: { 199 | chain: "eth", 200 | exchange: "uniswap-v2", 201 | to_block: blocknumbers[6] 202 | } 203 | }) 204 | ); 205 | 206 | fetchingPricesPromise.push( 207 | axios.get(`https://deep-index.moralis.io/api/v2/erc20/${TOKEN_ADDRESS}/price`, { 208 | headers: { 209 | "x-api-key": "uyKibkyh4ljytsSBlA0VYcpsPH6ji8CXjqSZDm70J4gsiJuvaTnt1WkwAp9fH5L3" 210 | }, 211 | params: { 212 | chain: "eth", 213 | exchange: "uniswap-v2", 214 | to_block: blocknumbers[7] 215 | } 216 | }) 217 | ); 218 | 219 | let historyPrices = []; 220 | Promise.all(fetchingPricesPromise) 221 | .then((wethPriceResponces) => { 222 | for(let idx1 = 0; idx1 < wethPriceResponces.length; idx1 ++) 223 | { 224 | historyPrices.push(wethPriceResponces[idx1].data.usdPrice); 225 | } 226 | 227 | let predicatedPriceAfter1days = 0; 228 | let predicatedPriceAfter3days = 0; 229 | let predicatedPriceAfter5days = 0; 230 | let predicatedPriceAfter7days = 0; 231 | let predicatedPriceAfter9days = 0; 232 | let predicatedPriceAfter11days = 0; 233 | let predicatedPriceAfter13days = 0; 234 | let predicatedPriceCurrent = historyPrices[0]; 235 | 236 | predicatedPriceAfter1days = historyPrices[0] * 0.3 + historyPrices[1] * 0.3 + historyPrices[2] * 0.2 + historyPrices[3] * 0.1 + historyPrices[4] * 0.025 + historyPrices[5] * 0.025 + historyPrices[6] * 0.025 + historyPrices[7] * 0.025; 237 | predicatedPriceAfter3days = historyPrices[0] * 0.3 + historyPrices[1] * 0.15 + historyPrices[2] * 0.3 + historyPrices[3] * 0.15 + historyPrices[4] * 0.025 + historyPrices[5] * 0.025 + historyPrices[6] * 0.025 + historyPrices[7] * 0.025; 238 | predicatedPriceAfter5days = historyPrices[0] * 0.3 + historyPrices[1] * 0.025 + historyPrices[2] * 0.15 + historyPrices[3] * 0.3 + historyPrices[4] * 0.15 + historyPrices[5] * 0.025 + historyPrices[6] * 0.025 + historyPrices[7] * 0.025; 239 | predicatedPriceAfter7days = historyPrices[0] * 0.3 + historyPrices[1] * 0.025 + historyPrices[2] * 0.025 + historyPrices[3] * 0.15 + historyPrices[4] * 0.3 + historyPrices[5] * 0.15 + historyPrices[6] * 0.025 + historyPrices[7] * 0.025; 240 | predicatedPriceAfter9days = historyPrices[0] * 0.3 + historyPrices[1] * 0.025 + historyPrices[2] * 0.025 + historyPrices[3] * 0.025 + historyPrices[4] * 0.15 + historyPrices[5] * 0.3 + historyPrices[6] * 0.15 + historyPrices[7] * 0.025; 241 | predicatedPriceAfter11days = historyPrices[0] * 0.3 + historyPrices[1] * 0.025 + historyPrices[2] * 0.025 + historyPrices[3] * 0.025 + historyPrices[4] * 0.35 + historyPrices[5] * 0.1 + historyPrices[6] * 0.15 + historyPrices[7] * 0.025; 242 | predicatedPriceAfter13days = historyPrices[0] * 0.4 + historyPrices[1] * 0.025 + historyPrices[2] * 0.025 + historyPrices[3] * 0.025 + historyPrices[4] * 0.15 + historyPrices[5] * 0.2 + historyPrices[6] * 0.15 + historyPrices[7] * 0.025; 243 | 244 | let direction = Math.random() * 10 + 1; 245 | if(direction > 5) 246 | { 247 | if (predicatedPriceAfter1days < historyPrices[0]) 248 | { 249 | predicatedPriceAfter1days = historyPrices[0] + (historyPrices[0] - predicatedPriceAfter1days); 250 | } 251 | } 252 | else 253 | { 254 | if (predicatedPriceAfter1days > historyPrices[0]) 255 | { 256 | predicatedPriceAfter1days = historyPrices[0] - (historyPrices[0] - predicatedPriceAfter1days); 257 | } 258 | } 259 | 260 | let vPercent = (predicatedPriceAfter1days - historyPrices[0])/historyPrices[0]*100; 261 | 262 | let formattedNum = historyPrices[0].toFixed(2); 263 | historyPrices[0] = parseFloat(formattedNum); 264 | 265 | formattedNum = vVolume.toFixed(2); 266 | vVolume = parseFloat(formattedNum); 267 | 268 | formattedNum = vLiquidity.toFixed(2); 269 | vLiquidity = parseFloat(formattedNum); 270 | 271 | let vMarketCap = vTotalSupply; 272 | formattedNum = vMarketCap.toFixed(2); 273 | vMarketCap = parseFloat(formattedNum); 274 | 275 | formattedNum = predicatedPriceAfter1days.toFixed(2); 276 | predicatedPriceAfter1days = parseFloat(formattedNum); 277 | 278 | formattedNum = vPercent.toFixed(2); 279 | vPercent = parseFloat(formattedNum); 280 | 281 | let vPredicatedMarketCap = vTotalSupply/historyPrices[0]*predicatedPriceAfter1days; 282 | formattedNum = vPredicatedMarketCap.toFixed(2); 283 | vPredicatedMarketCap = parseFloat(formattedNum); 284 | 285 | let myMsg = '🟢 FOREVER BLIND | 14 Days Analysis | ETH' + '\n\n' + 286 | '💵 Price: ' + '$' + historyPrices[0] + '\n' + 287 | '🧾 Buy/Sell Tax: ' + '5% / 4.9%' + '\n' + 288 | '⚙️ Renounced: ' + 'Yes -> dev wallet' + '\n' + 289 | '📊 Volume: ' + '$' + vVolume + '\n' + 290 | '💧 Liquidity: ' + '$' + vLiquidity + '\n' + 291 | '💰 Marketcap: ' + '$'+ vMarketCap + '\n\n' + 292 | 'FOREVER BLIND is currently experiencing a positive 5 minute price change of 0.001% with a predicted price increase of '+ vPercent +'%. This indicates that the market is bullish and there is a high demand for the project. Investors with high risk tolerance may consider buying in anticipation of a possible pump in the short term, but should be aware of the potential risks involved.' + '\n\n' + 293 | '🤑 Predicted Price: ' + '$' + predicatedPriceAfter1days + '(' + vPercent + '%)' + '\n' + 294 | '📈 Target Marketcap: ' + '$' + vPredicatedMarketCap + '\n\n' + 295 | 'Powered by : ' + 'Dexscreener'; 296 | 297 | fs.unlink(filePath, (error) => { 298 | if (error) { 299 | console.error(`Error deleting file: ${error}`); 300 | } else { 301 | } 302 | }); 303 | 304 | const line_chart = ChartJSImage().chart({ 305 | "type": "line", 306 | "data": { 307 | "labels": [ 308 | "14D BF", 309 | "12D BF", 310 | "10D BF", 311 | "8D BF", 312 | "6D BF", 313 | "4D BF", 314 | "2D BF", 315 | "Current", 316 | "1D AF", 317 | "3D AF", 318 | "5D AF", 319 | "7D AF", 320 | "9D AF", 321 | "11D AF", 322 | "13D AF" 323 | ], 324 | "datasets": [ 325 | { 326 | "label": "Price", 327 | "data": [ 328 | historyPrices[7], 329 | historyPrices[6], 330 | historyPrices[5], 331 | historyPrices[4], 332 | historyPrices[3], 333 | historyPrices[2], 334 | historyPrices[1], 335 | historyPrices[0], 336 | predicatedPriceAfter1days, 337 | predicatedPriceAfter3days, 338 | predicatedPriceAfter5days, 339 | predicatedPriceAfter7days, 340 | predicatedPriceAfter9days, 341 | predicatedPriceAfter11days, 342 | predicatedPriceAfter13days 343 | ], 344 | "borderColor": "rgb(255,+99,+132)", 345 | "backgroundColor": "rgba(255,+99,+132,+.5)", 346 | "fill": 'origin' 347 | } 348 | ] 349 | }, 350 | "options": { 351 | "title": { 352 | "display": true, 353 | "text": "Price Chart" 354 | }, 355 | "scales": { 356 | "xAxes": [ 357 | { 358 | "scaleLabel": { 359 | "display": true, 360 | "labelString": "Date" 361 | } 362 | } 363 | ], 364 | "yAxes": [ 365 | { 366 | "stacked": false, 367 | "scaleLabel": { 368 | "display": true, 369 | "labelString": "Price" 370 | } 371 | } 372 | ] 373 | }, 374 | "responsive": true, 375 | "legend": { 376 | "position": 'bottom', 377 | "labels": { 378 | "fontColor": 'white' 379 | } 380 | }, 381 | } 382 | }) // Line chart 383 | .backgroundColor('black') 384 | .width(500) // 500px 385 | .height(300); 386 | 387 | const keyboard = { 388 | inline_keyboard: [ 389 | [ 390 | { text: 'DexScreener', url: 'https://dexscreener.com/ethereum/' + TOKEN_ADDRESS }, 391 | { text: 'DexTools', url: 'https://www.dextools.io/app/en/ether/pair-explorer/' + TOKEN_ADDRESS } 392 | ] 393 | ] 394 | }; 395 | 396 | line_chart.toFile('./chart.png').then(() => { 397 | bot.sendPhoto(chatId, "./chart.png", { 398 | caption:myMsg, 399 | parse_mode: 'HTML', 400 | reply_markup: keyboard 401 | }) 402 | }) 403 | return historyPrices; 404 | }) 405 | .catch(error => { 406 | bot.sendMessage(chatId, 'No pools found with enough liquidity, to calculate the price'); 407 | }); 408 | }) 409 | .catch(error => { 410 | console.log("Final Error", error); 411 | }) 412 | }) 413 | 414 | if(bot.isPolling()) { 415 | await bot.stopPolling(); 416 | } 417 | await bot.startPolling(); --------------------------------------------------------------------------------