├── bitcoin-address.txt ├── btc_qrcode.png ├── LICENSE.md ├── scriptCoinGecko.gs ├── Readme.md └── scriptCoinPaprika.gs /bitcoin-address.txt: -------------------------------------------------------------------------------- 1 | bitcoin:bc1pgud5lk850jrk7ty3kyzazntwdnnl6xrnm2wm5trdz7myfkhccglskqmgdk -------------------------------------------------------------------------------- /btc_qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pedrojok01/Import-CryptoData-into-GoogleSheet/HEAD/btc_qrcode.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) <2021-2023> Pedrojok01 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /scriptCoinGecko.gs: -------------------------------------------------------------------------------- 1 | function onOpen() { 2 | SpreadsheetApp.getUi() 3 | .createMenu("CoinGecko") 4 | .addItem("Update", "CRYPTODATAJSON") 5 | .addToUi(); 6 | } 7 | 8 | function CRYPTODATA(symbol, colName) { 9 | const sheetData = SpreadsheetApp.getActiveSpreadsheet() 10 | .getSheetByName("data") 11 | .getDataRange() 12 | .getValues(); 13 | const col = sheetData[0].indexOf(colName); 14 | 15 | if (col === -1) return "datatype not found"; 16 | 17 | const row = sheetData.findIndex((row, i) => i > 0 && row[2] === symbol); 18 | return row === -1 ? "symbol not found" : sheetData[row][col]; 19 | } 20 | 21 | function CRYPTODATAJSON() { 22 | const ui = SpreadsheetApp.getUi(); 23 | const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("data"); 24 | 25 | const urls = [ 26 | "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=1&sparkline=false", 27 | "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=2&sparkline=false", 28 | "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=3&sparkline=false", 29 | ]; 30 | 31 | const fetchOptions = { muteHttpExceptions: true }; 32 | const responses = UrlFetchApp.fetchAll( 33 | urls.map((url) => ({ url, ...fetchOptions })) 34 | ); 35 | 36 | if (responses.some((res) => res.getResponseCode() === 429)) { 37 | ui.alert("too many requests"); 38 | return; 39 | } 40 | 41 | if (responses.some((res) => res.getResponseCode() !== 200)) { 42 | ui.alert("server error : http " + res.getResponseCode()); 43 | return; 44 | } 45 | 46 | const dataSet = responses.flatMap((res) => JSON.parse(res.getContentText())); 47 | 48 | const header = [ 49 | "id", 50 | "name", 51 | "symbol", 52 | "market_cap_rank", 53 | "current_price", 54 | "market_cap", 55 | "circulating_supply", 56 | "total_supply", 57 | "max_supply", 58 | "total_volume", 59 | "high_24h", 60 | "low_24h", 61 | "price_change_24h", 62 | "price_change_percentage_24h", 63 | "market_cap_change_24h", 64 | "market_cap_change_percentage_24h", 65 | "usd_percent_change_1y", 66 | "ath", 67 | "ath_change_percentage", 68 | "ath_date", 69 | "atl", 70 | "atl_change_percentage", 71 | "atl_date", 72 | "last_updated", 73 | ]; 74 | 75 | const rows = [ 76 | header, 77 | ...dataSet.map((data) => header.map((col) => data[col])), 78 | ]; 79 | const dataRange = sheet.getRange(1, 1, rows.length, rows[0].length); 80 | dataRange.setValues(rows); 81 | } 82 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 |
Fetch cryptodata direclty into your Google sheets from either Coingecko or Coinpaprika APIs for free. Enjoy!
19 | 20 |")` with params being : 86 | 87 | - coin : a single coin ticket like "ETH" or "BTC" or "XMR" 88 | - date : something like "2018-02-20" 89 | - type of data : can be "price", "volume_24h" or "market_cap" 90 | - quote : optional, defaults to usd, but can be set to "usd" or "btc" 91 | 92 | #### Get global data : 93 | 94 | `=CRYPTODATAGLOBAL("bitcoin_dominance_percentage")` 95 | 96 |
97 | 98 | # Update data 99 | 100 | - Click on the menu item, then on Update to refresh the data; 101 | - Then, you need to refresh your spreadsheet. One simple way is to add a new line at the top of your sheet, and to delete it right away. This small change will refresh all data automatically. 102 | 103 | Any issues, improvements, forks are welcomed. It is certainly not optimized, but it's working :) 104 | 105 |
106 | 107 |108 |117 | -------------------------------------------------------------------------------- /scriptCoinPaprika.gs: -------------------------------------------------------------------------------- 1 | function onOpen() { 2 | SpreadsheetApp.getUi() 3 | .createMenu("CoinPaprika") 4 | .addItem("Update", "CRYPTODATAJSON") 5 | .addToUi(); 6 | } 7 | 8 | function CRYPTODATA(symbol, colName) { 9 | var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("data"); 10 | var data = sheet.getDataRange().getValues(); 11 | var colIndex = data[0].indexOf(colName); 12 | 13 | if (colIndex === -1) { 14 | return "datatype not found"; 15 | } 16 | 17 | for (var i = 1; i < data.length; i++) { 18 | if (data[i][2] === symbol) { 19 | return data[i][colIndex]; 20 | } 21 | } 22 | 23 | return "symbol not found"; 24 | } 25 | 26 | function CRYPTODATAHISTORY(symbol, date, type, quote) { 27 | quote = quote || "usd"; 28 | 29 | const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("data"); 30 | const data = sheet.getDataRange().getValues(); 31 | const colIndex = data[0].indexOf("id"); 32 | 33 | if (colIndex === -1) { 34 | return "datatype not found"; 35 | } 36 | 37 | for (let i = 1; i < data.length; i++) { 38 | if (data[i][2] === symbol) { 39 | const coinId = data[i][colIndex]; 40 | const formattedDate = date instanceof Date ? date.toISOString() : date; 41 | const url = `https://api.coinpaprika.com/v1/tickers/${coinId}/historical?start=${formattedDate}&interval=5m&limit=1"e=${quote}`; 42 | 43 | const responseData = fetchUrl(url); 44 | return responseData[0].hasOwnProperty(type) 45 | ? responseData[0][type] 46 | : "price not found"; 47 | } 48 | } 49 | 50 | return "symbol not found"; 51 | } 52 | 53 | function CRYPTODATACOINDETAILS(coin_id, colName) { 54 | const param = encodeURI(coin_id); 55 | 56 | if (colName.indexOf("/") !== -1) { 57 | const [quote, property] = colName.split("/"); 58 | const url = 59 | "https://api.coinpaprika.com/v1/tickers/" + param + "?quotes=" + quote; 60 | const responseData = fetchUrl(url); 61 | 62 | if ( 63 | responseData.hasOwnProperty("error") && 64 | responseData["error"] === "id not found" 65 | ) { 66 | return "coin_id not found"; 67 | } 68 | 69 | if (responseData["quotes"][quote].hasOwnProperty(property)) { 70 | return responseData["quotes"][quote][property]; 71 | } else { 72 | return "property not found"; 73 | } 74 | } else { 75 | const url = "https://api.coinpaprika.com/v1/coins/" + param; 76 | const responseData = fetchUrl(url); 77 | 78 | if ( 79 | responseData.hasOwnProperty("error") && 80 | responseData["error"] === "id not found" 81 | ) { 82 | return "coin_id not found"; 83 | } 84 | 85 | if (responseData.hasOwnProperty(colName)) { 86 | return responseData[colName]; 87 | } else { 88 | return "property not found"; 89 | } 90 | } 91 | } 92 | 93 | function CRYPTODATAJSON() { 94 | const ui = SpreadsheetApp.getUi(); 95 | const ss = SpreadsheetApp.getActiveSpreadsheet(); 96 | const sheet = ss.getSheetByName("data"); 97 | 98 | const url = "https://api.coinpaprika.com/v1/tickers?quotes=USD,BTC"; 99 | const dataAll = fetchUrl(url); 100 | const dataSet = dataAll.sort((a, b) => (a.rank > b.rank ? 1 : -1)); 101 | 102 | const rows = [headers]; 103 | 104 | dataSet.forEach((data) => { 105 | const rowData = headers.map((header) => { 106 | if (header.startsWith("btc_")) { 107 | const key = header.slice(4); 108 | return data.quotes["BTC"][key] || ""; 109 | } 110 | if (header.startsWith("usd_")) { 111 | const key = header.slice(4); 112 | return data.quotes["USD"][key] || ""; 113 | } 114 | return data[header] || ""; 115 | }); 116 | rows.push(rowData); 117 | }); 118 | 119 | const dataRange = sheet.getRange(1, 1, rows.length, rows[0].length); 120 | dataRange.setValues(rows); 121 | } 122 | 123 | /* UTILS: 124 | ***********/ 125 | 126 | function fetchUrl(url) { 127 | const response = UrlFetchApp.fetch(url, { muteHttpExceptions: true }); 128 | RESPONSECODE(response); 129 | return JSON.parse(response.getContentText()); 130 | } 131 | 132 | function RESPONSECODE(v) { 133 | var responseCode = v.getResponseCode(); 134 | 135 | if (responseCode === 429) { 136 | throw new Error("Too many requests"); 137 | } else if (responseCode !== 200) { 138 | throw new Error("Server error"); 139 | } 140 | } 141 | 142 | /* CRYPTODATAJSON() - DATA HEADERS 143 | **********************************/ 144 | 145 | const headers = [ 146 | "id", 147 | "name", 148 | "symbol", 149 | "rank", 150 | "circulating_supply", 151 | "total_supply", 152 | "max_supply", 153 | "beta_value", 154 | "first_data_at", 155 | "last_updated", 156 | "btc_price", 157 | "btc_volume_24h", 158 | "btc_volume_24h_change_24h", 159 | "btc_market_cap", 160 | "btc_market_cap_change_24h", 161 | "btc_percent_change_15m", 162 | "btc_percent_change_30m", 163 | "btc_percent_change_1h", 164 | "btc_percent_change_6h", 165 | "btc_percent_change_12h", 166 | "btc_percent_change_24h", 167 | "btc_percent_change_7d", 168 | "btc_percent_change_30d", 169 | "btc_percent_change_1y", 170 | "btc_ath_price", 171 | "btc_ath_date", 172 | "btc_percent_from_price_ath", 173 | "usd_price", 174 | "usd_volume_24h", 175 | "usd_volume_24h_change_24h", 176 | "usd_market_cap", 177 | "usd_market_cap_change_24h", 178 | "usd_percent_change_15m", 179 | "usd_percent_change_30m", 180 | "usd_percent_change_1h", 181 | "usd_percent_change_6h", 182 | "usd_percent_change_12h", 183 | "usd_percent_change_24h", 184 | "usd_percent_change_7d", 185 | "usd_percent_change_30d", 186 | "usd_percent_change_1y", 187 | "usd_ath_price", 188 | "usd_ath_date", 189 | "usd_percent_from_price_ath", 190 | ]; 191 | --------------------------------------------------------------------------------If you like it, a donation is always welcome!
109 | 110 | [](https://raw.githubusercontent.com/Pedrojok01/Import-CryptoData-into-GoogleSheet/main/bitcoin-address.txt) 111 | 112 | ``` 113 | BTC: bc1pgud5lk850jrk7ty3kyzazntwdnnl6xrnm2wm5trdz7myfkhccglskqmgdk 114 | ``` 115 | 116 |