Last active
September 11, 2023 12:10
-
-
Save trumad/75a4013ace429c3854e967d6bbe1c6fc to your computer and use it in GitHub Desktop.
See multiple tradingview windows side by side, hopefully without ads and popups.
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
# First install webview: | |
# pip install pywebview | |
# Then create a config.json file in the same folder with the following options: | |
""" | |
{ | |
"content":[ | |
{ | |
"exchange":"Bitstamp", | |
"ticker":"BTCUSD", | |
"interval": 1440 | |
}, | |
{ | |
"exchange":"Binance", | |
"ticker":"ETHUSD" | |
}, | |
{ | |
"exchange":"Binance", | |
"ticker":"ADAUSD" | |
}, | |
{ | |
"exchange":"Binance", | |
"ticker":"DOTUSD" | |
} | |
], | |
"screen-width":3840, | |
"screen-height":2180, | |
"no_of_columns":2, | |
"interval": 60 | |
} | |
""" | |
# Set your max screen width and height (Or use trial & error!) | |
# Set your exchanges and ticker pairs | |
# Decide how many colums you want to divide the screen into | |
# Decide whether you want a longer/shorter interval. Only set to something a free account can access. | |
# Then run: | |
# python tradingViewMultipleWindows.py | |
import json | |
import math | |
import webview | |
#import pyautogui | |
javascript = r""" | |
function sleep(ms) { // usage: await sleep(4000) | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
//Check the DOM for changes and run a callback function on each mutation | |
function observeDOM(callback) { | |
var mutationObserver = new MutationObserver(function (mutations) { //https://davidwalsh.name/mutationobserver-api | |
mutations.forEach(function (mutation) { | |
//console.log(mutation) | |
callback(mutation) // run the user-supplied callback function, | |
}); | |
}); | |
// Keep an eye on the DOM for changes | |
mutationObserver.observe(document.body, { //https://blog.sessionstack.com/how-javascript-works-tracking-changes-in-the-dom-using-mutationobserver-86adc7446401 | |
attributes: true, | |
// characterData: true, | |
childList: true, | |
subtree: true, | |
// attributeOldValue: true, | |
// characterDataOldValue: true, | |
// attributeFilter: ["class"] // We're really only interested in stuff that has a className | |
}); | |
} | |
observeDOM(doDomStuff); | |
cleanUpPage(); | |
async function cleanUpPage(){ | |
while (true){ | |
await sleep(15000); | |
closeBackDrop(document); | |
removeGoogleAds(document); | |
} | |
} | |
function doDomStuff(mutation){ | |
if (!mutation.target.className) { return } | |
if (!mutation.target.className === "") { return } | |
if (mutation.target.className.includes("chart-page")) { // basically ends up being the whole page, sometimes. | |
// closeBackDrop(mutation.target); | |
// removeGoogleAds(mutation.target); | |
} | |
if (mutation.target.className.includes("toast-")) { | |
// removeGoogleAds(mutation.target); | |
} | |
if (mutation.target.className.includes("layout__area--top")) { // the bar at the top of the screen | |
removeStartFreeTrialButton(mutation.target); | |
} | |
if (mutation.target.className.includes("toast-positioning-wrapper")) { // this fires when a popup happens | |
// console.log(mutation.target); | |
removePopups(mutation.target); | |
} | |
/* if (mutation.target.textContent.includes("Take your trading to the next level")){ | |
console.log(mutation.target); | |
}*/ | |
/* if (mutation.target.querySelector("iframe[id*=google_ads_iframe]")){ | |
console.log(mutation.target); | |
}*/ | |
if (mutation.target.className.includes("layout__area--center")){ | |
// console.log(mutation.target); | |
removePressAndHoldNotification(mutation.target); | |
} | |
} | |
function removeGoogleAds(el){ | |
if (document.querySelector("iframe[id*=google_osd_static_frame]")){ | |
document.querySelector("iframe[id*=google_osd_static_frame]").remove(); | |
} | |
if (!document.querySelector("iframe[id*=google_ads_iframe]")){return} | |
var frame = document.querySelector("iframe[id*=google_ads_iframe]"); | |
// console.log(frame); | |
var closestWrapper = frame.closest("[class*=toast-positioning-wrapper-]"); | |
if (!closestWrapper){return} | |
var closeButton = closestWrapper.querySelector("[class*=close-button-]"); | |
if (!closeButton){return} | |
closeButton.click(); | |
console.log("BYE GOOGLE!"); | |
// document.querySelector("[id*=div-gpt-ad]").closest("[class*=toast-positioning-wrapper-]").querySelector("[class*=close-button-]").click() | |
} | |
function removeStartFreeTrialButton(el){ | |
if (!el.textContent.includes("Start free trial")){return} | |
if (!el.querySelector("#header-toolbar-start-trial")){return} | |
el.querySelector("#header-toolbar-start-trial").parentElement.remove(); | |
} | |
function removePressAndHoldNotification(el){ | |
if (!el.textContent.includes("Press and hold")){return} | |
if (!el.querySelector("[class*=container-] > [class*=closeButton]")){return} | |
el.querySelector("[class*=container-] > [class*=closeButton]").click(); | |
} | |
function removePopups(el){ | |
if (el.textContent.includes("This website uses cookies")){ | |
if (!el.querySelector("button")){return}; | |
el.querySelector("button").click(); //accept cookies | |
} | |
if (el.textContent.includes("Unlock the full power of TradingView")){ // free trial ad | |
if (!el.querySelector("[class*=close-icon-]")){return}; | |
el.querySelector("[class*=close-icon-]").click(); // close | |
} | |
} | |
function closeBackDrop(el){ | |
if (!el.querySelector("[class*=backdrop]")){return} | |
var backDrop = el.querySelector("[class*=backdrop]"); // opaque div that covers the whole page | |
if (!backDrop.nextElementSibling){return} | |
var wrap = backDrop.nextElementSibling; // "sign up" notification | |
wrap.remove(); // remove sign up notiication | |
backDrop.remove(); // remove opaque backdrop | |
} | |
""" | |
def windows(): | |
"""""" | |
origWindow.resize(200,50) | |
origWindow.move(0,0) | |
config_details = get_config_details() | |
total_width = config_details['screen-width'] | |
total_height = config_details['screen-height'] | |
no_of_windows = len(config_details['content']) | |
print("Current window setup = {}x{}".format(total_width, total_height)) | |
#print("No. of windows to create: {}".format(no_of_windows)) | |
no_of_columns_to_make = config_details['no_of_columns'] | |
print("No. of columns to make: {}".format(no_of_columns_to_make)) | |
x_position = 0 | |
y_position = 0 | |
if no_of_windows <= no_of_columns_to_make: | |
no_of_rows_to_make = 1 | |
else: | |
no_of_rows_to_make = math.ceil(no_of_windows / 2) | |
print("No of rows to make: {}".format(no_of_rows_to_make)) | |
#print("no of rows: {}".format(no_of_rows_to_make)) | |
column = 1 | |
row = 1 | |
current_grid = 1 | |
for each in config_details['content']: | |
#print(each) | |
if 'interval' in config_details: | |
the_url = 'https://uk.tradingview.com/chart/?symbol={}%3A{}&interval={}'.format(each['exchange'], each['ticker'], config_details['interval']) | |
else: | |
the_url = 'https://uk.tradingview.com/chart/?symbol={}%3A{}'.format(each['exchange'], each['ticker']) | |
#print(the_url) | |
win = webview.create_window("Tradingview - {} - Kill the terminal running the python to close".format(each['ticker']), the_url, frameless=False) | |
win.evaluate_js(javascript) | |
win.resize(total_width/no_of_columns_to_make, total_height/no_of_rows_to_make) | |
# placement of windows | |
#print("current_grid: {}".format(current_grid)) | |
win.move(x_position, y_position) | |
#print("Current row= {}".format(row)) | |
#print("Current col= {}".format(column)) | |
if column == no_of_columns_to_make: | |
row += 1 | |
column = 1 | |
else: | |
column += 1 | |
#print(row, column) | |
x_position = (total_width / no_of_columns_to_make) * (column - 1) | |
y_position = (total_height / no_of_rows_to_make) * (row - 1) | |
current_grid += 1 | |
#print("new x: {}".format(x_position)) | |
#print("new y: {}".format(y_position)) | |
origWindow.destroy() | |
def get_config_details(): | |
"""""" | |
with open('config.json') as the_file: | |
data = json.load(the_file) | |
return data | |
if __name__ == '__main__': | |
# Master window | |
origWindow = webview.create_window('Launching', html='<h1>Launching...</h1>', frameless=True) | |
# win2 = webview.create_window('BTC/GBP', 'https://uk.tradingview.com/chart/?symbol=BITSTAMP%3ABTCUSD', frameless=True) | |
webview.start(windows) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment