Last active
March 30, 2023 20:27
-
-
Save ubarbaxor/e4e68cc2061bdab43ba62838ecebdc15 to your computer and use it in GitHub Desktop.
Quick margin / PNL ticker + CSV extraction for degens. Runs as-is or in ViolentMonkey.
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 YOLOREKT UI EDITS | |
// @namespace Violentmonkey Scripts | |
// @match https://www.yolorekt.finance/game?gametype=G_LVG | |
// @grant none | |
// @version 1.1.5d | |
// @author ubarbaxor 'Fishotron' will fork for wood | |
// @description If you like this, feel free to buy me a coffee. ETH/USDC(Polygon) : 0x7cd974D9Ce1014a3Feb5f359c5D9b83174209782 | |
// @downloadURL https://gist.github.com/ubarbaxor/e4e68cc2061bdab43ba62838ecebdc15/raw/fisherTick.js | |
// @updateURL https://gist.github.com/ubarbaxor/e4e68cc2061bdab43ba62838ecebdc15/raw/fisherTick.js | |
// @homepageURL https://gist.github.com/ubarbaxor/e4e68cc2061bdab43ba62838ecebdc15 | |
// ==/UserScript== | |
// DATA SCRAPING / EXTRACTION | |
dataClasses = [ | |
'status', | |
'asset', | |
'entry', | |
'bidamount', | |
'bust', | |
'multiplier', | |
'exit', | |
'pandl', | |
] | |
format = data => { | |
const r = data | |
.replace(/[^\x00-\x7F]/g, '') // remove non-ascii | |
.replace(',', '') // clean commas from financials | |
return r.includes('$')// clean dollar sign in numbers | |
? Number(r.replace('$', '')) | |
: r | |
} | |
extractData = bidElem => dataClasses.reduce((data, index) => { | |
const dedupLast = bidElem.querySelectorAll(`.${index}`) | |
const dataText = dedupLast[dedupLast.length - 1].outerText | |
return { | |
...data, | |
[index]: format(dataText) | |
} | |
}, {}) | |
sum = field => arr => arr.reduce((total, item) => total + item[field], 0) | |
getBids = _ => [...document.getElementsByClassName('yourbids_table_row')] | |
// POLLUTE SCOPE FOR CONVENIENCE | |
Object.defineProperties(window, { | |
bids: { | |
get: getBids | |
}, | |
bidsData: { | |
get: function () { return window.bids | |
.map(extractData) } | |
}, | |
openBids: { | |
get: function () { return window.bidsData | |
.filter(d => d.status === 'Open') | |
}, | |
}, | |
lockedMargin: { | |
get: function () { | |
return sum('bidamount')(window.openBids) | |
} | |
}, | |
unrealised: { | |
get: function () { | |
return sum('pandl')(window.openBids) | |
} | |
} | |
}) | |
// CSV EXPORT | |
const genCSV = _ => { | |
const bid2arr = dataBid => dataClasses.map(c => dataBid[c]) | |
const genRow = arr => arr.join(',') | |
const header = genRow(dataClasses) | |
const blob = [ | |
header, | |
...bidsData.map(bid => genRow(bid2arr(bid))) | |
].join('\n') | |
return blob | |
} | |
const exportCSV = (filename = 'yolorekt.csv') => { | |
const blob = new Blob([genCSV()], {type: 'text/csv'}) | |
if (window.navigator.msSaveOrOpenBlob) { | |
window.navigator.msSaveBlob(blob, filename) | |
} | |
else { | |
const el = document.createElement('a') | |
el.href = window.URL.createObjectURL(blob) | |
el.download = filename | |
document.body.appendChild(el) | |
el.click() | |
document.body.removeChild(el) | |
} | |
} | |
// UI EDITS | |
const colors = { | |
win: 'rgb(0, 194, 19)', | |
grey: 'rgb(73, 76, 80)', | |
loss: 'rgb(221, 14, 83)', | |
white: 'rgb(255, 255, 255)', | |
} | |
// ANNOYING SELECTABLE BUTTON FIX | |
roiCalc = document.querySelector('.roiCalculator') | |
for (tabsBtn of roiCalc.parentElement.children) { | |
tabsBtn.style.userSelect = 'none' | |
} | |
// CSV EXPORTER | |
exportBtn = roiCalc.cloneNode(true) | |
exportBtn.classList.remove('roiCalculator') | |
exportBtn.style.userSelect = 'none' | |
exportBtn.innerHTML = 'EXPORT BIDS' | |
exportBtn.onclick = _ => exportCSV() | |
roiCalc.after(exportBtn) | |
// LOCKED MARGIN / PNL TICKER | |
const balance = document.querySelector('[href="/game/wallet"] span') | |
let lockedEl = document.getElementById('marginLocked') | |
if (!lockedEl) { | |
lockedEl = balance.cloneNode(true) | |
lockedEl.id = 'marginLocked' | |
lockedEl.dataset['hint'] = 'Locked margin' | |
lockedEl.classList.add( | |
'hint--medium', | |
'hint--bottom', | |
'hint--rounded' | |
) | |
lockedEl.style.color = colors.grey | |
lockedEl.style.margin = '1em' | |
lockedEl.style.textAlign = 'center' | |
lockedEl.innerText = '' | |
balance.before(lockedEl) | |
} | |
let PandEl = document.getElementById('profitsAnLosses') | |
if (!PandEl) { | |
PandEl = balance.cloneNode(true) | |
PandEl.id = 'profitsAnLosses' | |
PandEl.dataset['hint'] = 'Open PNL' | |
PandEl.classList.add( | |
'hint--small', | |
'hint--bottom', | |
'hint--rounded' | |
) | |
PandEl.style.textAlign = 'center' | |
PandEl.innerText = '' | |
lockedEl.before(PandEl) | |
} | |
const updateLocked = _ => { | |
lockedEl.innerText = lockedMargin.toFixed(2) | |
} | |
const updatePnL = _ => { | |
PandEl.innerText = unrealised.toFixed(2) | |
PandEl.style.color = unrealised > 0 | |
? colors.win : unrealised < 0 | |
? colors.loss | |
: colors.grey | |
} | |
// Auto-close toasts | |
let cleanupToasts = true | |
const updateToasts = _ => { | |
const latestToast = document.querySelector('[role="alert"]') | |
if (!latestToast) | |
return | |
// Set latest toast to disappear | |
if (cleanupToasts && !latestToast.matches('.timed')) { | |
latestToast.classList.add('timed') | |
setTimeout(_ => { // can't just remove() toast because reasons | |
const deleteButton = latestToast.querySelector('button') | |
if (deleteButton) | |
deleteButton.click() | |
}, 3000) | |
} | |
} | |
// CASHOUT ALL | |
window.closeAll = _ => { | |
const openBEls = bids.filter(b => b | |
.querySelector('.status') | |
.matches('.open')) | |
const closeBtns = openBEls.map(bidEl => bidEl.querySelector('.cashout')) | |
closeBtns.forEach(btn => btn.click()) | |
} | |
closeAllBtn = exportBtn.cloneNode(true) | |
closeAllBtn.innerHTML = 'CLOSE ALL' | |
closeAllBtn.onclick = _ => { window.closeAll() } | |
exportBtn.after(closeAllBtn) | |
const updateCloseAll = _ => { | |
if (!openBids.length) { | |
closeAllBtn.disabled = true | |
closeAllBtn.style.color = colors.grey | |
} else { | |
closeAllBtn.removeAttribute('disabled') | |
closeAllBtn.style.color = unrealised > 0 | |
? colors.win : unrealised < 0 | |
? colors.loss | |
: colors.white | |
} | |
} | |
// BATCH BIDS | |
amountInput = document.querySelector('input[type=dial]') | |
batchInput = amountInput.cloneNode('true') | |
bidBtn = document.querySelector('.bidInput') | |
bidBox = bidBtn.parentElement | |
batchBox = bidBox.cloneNode(true) | |
batchBtn = batchBox.querySelector('.bidInput') | |
batchInput.placeholder = '0' | |
batchBtn.innerHTML = 'BATCH' | |
bidBox.after(batchBox) | |
batchBtn.before(batchInput) | |
batchBid = async _ => { | |
const getCount = _ => Number(batchInput.value) | |
const setCount = value => { batchInput.value = value } | |
const bidCount = getCount() | |
const bidamount = Number(amountInput.value) | |
const sendBid = amount => { | |
const previousValue = amountInput.value | |
amountInput.value = `${amount}` | |
amountInput._valueTracker.setValue(previousValue) | |
amountInput.dispatchEvent(new Event('change', { bubbles: true })) | |
bidBtn.click() | |
// UI cooldown | |
return new Promise((resolve) => { setImmediate(resolve, 10) }) | |
} | |
while ( getCount() ) { | |
setCount(getCount() - 1) | |
await sendBid(bidamount) | |
} | |
} | |
let BBTO | |
const resetBBtn = _ => { | |
batchBtn.innerHTML = 'BATCH' | |
clearTimeout(BBTO) | |
} | |
batchBtn.onclick = _ => { | |
batchBtn.innerHTML = 'DOUBLE-CLICK 😉' | |
clearTimeout(BBTO) | |
BBTO = setTimeout(resetBBtn, 1000) | |
} | |
batchBtn.ondblclick = _ => { | |
batchBid() | |
resetBBtn() | |
} | |
batchBtn.disabled = false | |
// Updates | |
const refreshTick = _ => { | |
updateLocked() | |
updatePnL() | |
updateToasts() | |
updateCloseAll() | |
} | |
setInterval(refreshTick, 500) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment