Last active
July 10, 2022 20:39
-
-
Save zobzn/95a427d546624a3215e1d83c8916c98f to your computer and use it in GitHub Desktop.
etoro-watchlist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name etoro watchlist | |
// @version 0.0.1 | |
// @author zobzn | |
// @namespace https://gist.github.com/zobzn/95a427d546624a3215e1d83c8916c98f | |
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | |
// @description try to take over the world! | |
// @updateURL https://gist.githubusercontent.com/zobzn/95a427d546624a3215e1d83c8916c98f/raw/etoro-watchlist.js | |
// @downloadURL https://gist.githubusercontent.com/zobzn/95a427d546624a3215e1d83c8916c98f/raw/etoro-watchlist.js | |
// @match *://www.etoro.com/watchlists | |
// @match *://www.etoro.com/markets/* | |
// @match *://www.etoro.com/markets/*/chart | |
// @require https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js | |
// @require https://cdn.jsdelivr.net/npm/luxon@3.0.1/build/global/luxon.min.js | |
// @run-at document-end | |
// @grant GM_setValue | |
// @grant GM_getValue | |
// @grant GM_setClipboard | |
// @grant GM_addStyle | |
// @grant unsafeWindow | |
// @grant window.close | |
// @grant window.focus | |
// @grant window.onurlchange | |
// ==/UserScript== | |
(async () => { | |
"use strict"; | |
const { keyBy, pick, omit } = _; | |
const { DateTime } = luxon; | |
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); | |
const f = (...args) => fetch(...args).then((res) => res.json()); | |
const $ = (selector, context = document) => context.querySelector(selector); | |
const $$ = (selector, context = document) => [ | |
...context.querySelectorAll(selector), | |
]; | |
const waitFor = async (selector, callback) => { | |
do { | |
const elements = $$(selector); | |
if (elements.length) { | |
await callback(elements); | |
break; | |
} else { | |
await sleep(500); | |
} | |
} while (true); | |
}; | |
const waitForEach = async (selector, callback) => { | |
await waitFor(selector, async (elements) => { | |
for (const el of elements) { | |
await callback(el); | |
} | |
}); | |
}; | |
GM_addStyle(` | |
.price-range .low {color: red; } | |
`); | |
if (false) { | |
const [d1, d2, d3] = await Promise.all([ | |
f( | |
"https://api.etorostatic.com/sapi/trade-real/instruments/bulk-slim?InstrumentDataFilters=TradingData&bulkNumber=1&totalBulks=1" | |
).then((r) => keyBy(r.Instruments, "InstrumentID")), | |
f( | |
"https://api.etorostatic.com/sapi/instrumentsmetadata/V1.1/instruments/bulk?bulkNumber=1&totalBulks=1" | |
).then((r) => keyBy(r.InstrumentDisplayDatas, "InstrumentID")), | |
f( | |
"https://www.etoro.com/sapi/trade-real/instruments?InstrumentDataFilters=Activity,Rates,ActivityInExchange" | |
).then((r) => keyBy(r.Rates, "InstrumentID")), | |
]); | |
const symbols = Object.keys(d1) | |
.map((k) => ({ ...d1[k], ...d2[k], rates: d3[k] })) | |
.map((it) => ({ ...it, id: it.InstrumentID, code: it.SymbolFull })); | |
const symbolsByID = keyBy(symbols, "id"); | |
const symbolsByCode = keyBy(symbols, "code"); | |
console.log(pick(symbolsByCode, ["NSDQ100", "BTC"])); | |
} | |
const onInit = async ({ url }) => { | |
await waitForEach( | |
"#watchlist-instruments .et-table-row .bar-info", | |
(some) => { | |
const row = some.closest(".et-table-row"); | |
const barInfo = $(".bar-info", row); | |
const barInfoCell = barInfo.closest(".et-table-cell"); | |
// barInfoCell.style.maxWidth = "60px"; | |
barInfo.innerHTML = `<div class="spread"></div> - <div class="from-high"></div>`; | |
} | |
); | |
setInterval(() => { | |
$$( | |
"#watchlist-instruments .et-table-row .price-range .low:not(:empty)" | |
).forEach((some) => { | |
const row = some.closest(".et-table-row"); | |
const range = $(".price-range", row); | |
const min = parseFloat($(".price-range .low", row).innerText); | |
const max = parseFloat($(".price-range .high", row).innerText); | |
const sell = parseFloat( | |
$('[automation-id="buy-sell-button-container-sell"] .price', row) | |
.innerText | |
); | |
const buy = parseFloat( | |
$('[automation-id="buy-sell-button-container-buy"] .price', row) | |
.innerText | |
); | |
const fromHighData = ((sell / max) * 100).toFixed(2); | |
const spreadData = `${(buy - sell).toFixed(2)} (${( | |
(100 * (buy - sell)) / | |
buy | |
).toFixed(2)}%)`; | |
if ($(".from-high", row).innerText !== fromHighData) { | |
$(".from-high", row).innerHTML = fromHighData; | |
} | |
if ($(".spread", row).innerText !== spreadData) { | |
$(".spread", row).innerHTML = spreadData; | |
} | |
}); | |
}, 500); | |
}; | |
window.addEventListener("urlchange", ({ url }) => onInit({ url })); | |
onInit({ url: location.href }); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment