Steps to get up and running:
1) Create an Unbuntu 17.10 server with at least 2GB RAM
2) `apt update` all dependencies
3) Install Docker and Docker-compose
4) Optional but strongly recommended, install a strong firewall with bruteforce detection.
`apt install apf-firewall`
To install BFD, see: [http://www.webhostgear.com/60.html](http://www.webhostgear.com/60.html)
Configure your ports as desired. It is strongly suggested to run your VNC on a non-standard port for security purposes
4) Run `sudo docker-compose up`
5) Connect to your Docker container through VNC Viewer
6) Right click on the Desktop > Applications > Shell > Bash
7) `npm run setup` will run Autoview setup script (and load the Autoview extension automatically)
8) `npm run start` will run Tradingview login script (and load the Autoview extension automatically)
9) Open up a new tab `localhost:9222` and click Autoview. Now you can see the debuggingo output for autoview to see if its working.
10) Setup your TradingView.com alerts and watch them get triggered automatically 24/7!
version: "3"
services:
virtual-display:
build: "." # rebuilds the image upon running if needed.
image: "autoviewbot:latest"
working_dir: /home/node/app
# This command runs the NodeJS server using ts-node
command: >
sh -c "
echo Starting Virtual Display Server... &&
./launch-virtual-display.sh
"
ports:
- "3903:3903" # HOST:CONTAINER - NOTE THIS PORT MUST MATCH THE -rfbport #### SET IN ./launch-virtual-display.sh
environment:
- VNC_SERVER_PASSWORD=yourpass # this is your VNC password to connect
# On host, run `timedatectl set-timezone UTC` to set the Timezone , change UTC with your actual timezone
restart: always
user: node
privileged: true
volumes: # use local disk data instead of image data. Useful for localhost development mode
- ./:/home/node/app/
- /etc/localtime:/etc/localtime:ro # this syncs the Host server time into the Docker Container
#!/bin/bash
# Based on: http://www.richud.com/wiki/Ubuntu_Fluxbox_GUI_with_x11vnc_and_Xvfb
main() {
log_i "Starting xvfb virtual display..."
launch_xvfb
log_i "Starting window manager..."
launch_window_manager
log_i "Starting VNC server..."
run_vnc_server
}
launch_xvfb() {
local xvfbLockFilePath="/tmp/.X1-lock"
if [ -f "${xvfbLockFilePath}" ]
then
log_i "Removing xvfb lock file '${xvfbLockFilePath}'..."
if ! rm -v "${xvfbLockFilePath}"
then
log_e "Failed to remove xvfb lock file"
exit 1
fi
fi
# Set defaults if the user did not specify envs.
export DISPLAY=${XVFB_DISPLAY:-:1}
local screen=${XVFB_SCREEN:-0}
local resolution=${XVFB_RESOLUTION:-1280x960x24}
local timeout=${XVFB_TIMEOUT:-5}
# Start and wait for either Xvfb to be fully up or we hit the timeout.
Xvfb ${DISPLAY} -screen ${screen} ${resolution} &
local loopCount=0
until xdpyinfo -display ${DISPLAY} > /dev/null 2>&1
do
loopCount=$((loopCount+1))
sleep 1
if [ ${loopCount} -gt ${timeout} ]
then
log_e "xvfb failed to start"
exit 1
fi
done
}
launch_window_manager() {
local timeout=${XVFB_TIMEOUT:-5}
# Start and wait for either fluxbox to be fully up or we hit the timeout.
fluxbox &
local loopCount=0
until wmctrl -m > /dev/null 2>&1
do
loopCount=$((loopCount+1))
sleep 1
if [ ${loopCount} -gt ${timeout} ]
then
log_e "fluxbox failed to start"
exit 1
fi
done
}
run_vnc_server() {
local passwordArgument='-nopw'
if [ -n "${VNC_SERVER_PASSWORD}" ]
then
local passwordFilePath="${HOME}/.x11vnc.pass"
if ! x11vnc -storepasswd "${VNC_SERVER_PASSWORD}" "${passwordFilePath}"
then
log_e "Failed to store x11vnc password"
exit 1
fi
passwordArgument=-"-rfbauth ${passwordFilePath}"
log_i "The VNC server will ask for a password"
else
log_w "The VNC server will NOT ask for a password"
fi
x11vnc -rfbport 3903 -shared -display ${DISPLAY} -forever ${passwordArgument} &
wait $!
}
log_i() {
log "[INFO] ${@}"
}
log_w() {
log "[WARN] ${@}"
}
log_e() {
log "[ERROR] ${@}"
}
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ${@}"
}
control_c() {
echo ""
exit
}
trap control_c SIGINT SIGTERM SIGHUP
main
exit
{
"name": "chrome-headless-autoview-tradingview-bot",
"version": "0.0.1",
"description": "A virtual Chrome instance that run the Autoview bot while logged into TradingView.com, to enable serverside rendering of all AutoView bot commands.",
"author": "Cryptonyght",
"license": "MIT",
"repository": "",
"main": "start.sh",
"dependencies": {
"chromeless": "^1.5.2"
},
"devDependencies": {
"@types/node": "^10.1.0",
"make-runnable": "^1.3.6",
"npm-run-all": "^4.1.3",
"ts-node": "^6.0.3",
"tslib": "^1.9.1",
"typescript": "^2.8.3",
"zip-dir": "^1.0.2"
},
"scripts": {
"server": "docker-compose up",
"chrome": "npm run loadChrome:withextension",
"setup": "run-p loadChrome:withextension autoviewSetup",
"start": "run-p loadChrome:withextension tradingViewLogin",
"loadChrome:withextension": "google-chrome-stable --user-data-dir=\"chrome-profile\" --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222 --load-extension=\\extension",
"run:zipdir": "npm run clean:zipdir && node zipdir.js",
"clean:zipdir": "rimraf -- autoview-trading-bot.tar.gz",
"docker:build": "docker build -t autoviewbot:latest .",
"autoviewSetup": "ts-node bot-setup.ts autoviewSetup",
"tradingViewLogin": "ts-node bot.ts tradingViewLogin",
"loadChrome": "google-chrome-stable --user-data-dir=\"chrome-profile\" --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222",
"build": "tsc",
"clean": "rimraf -- node_modules",
"npm:install": "npm install",
"loadAutoview:headless": "google-chrome-stable --disable-gpu --headless --remote-debugging-port=9222 --load-extension=\\extension"
}
}
// This file just automates logging into TradingView.com - only a nice to have but can be extended to do anything on any website
import { Chromeless } from 'chromeless';
declare var TradingView;
// Make this runnable from package.json through NPM scripts using `make-runnable`
module.exports = {
loadAutoview: async function () {
const chromeless = new Chromeless({
launchChrome: true
});
const screenshot = await
chromeless
.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3430.0 Safari/537.36')
// .setViewport({width: 800, height: 600, scale: 1})
.goto('chrome-extension://okdhadoplaoehmeldlpakhpekjcpljmb/_generated_background_page.html')
.wait(2000)
.screenshot()
.catch((err) => {
console.error(err);
});
console.log(screenshot); // prints local file path or S3 url
// await chromeless.end();
},
tradingViewSignout: async function () {
const chromeless = new Chromeless({
launchChrome: true
});
const screenshot = await
chromeless
.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3430.0 Safari/537.36')
// .setViewport({width: 1920, height: 1080, scale: 1})
.goto('https://www.tradingview.com/')
.wait(4000)
.evaluate(() => {
if (TradingView.isPro()) {
TradingView.signOut();
return false;
}
})
.screenshot()
.catch((err) => {
console.error(err);
});
console.log(screenshot); // prints local file path or S3 url
await chromeless.end();
},
tradingViewLogin: async function () {
const chromeless = new Chromeless({
launchChrome: true,
waitTimeout: 20000
});
const screenshot = await chromeless
.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3430.0 Safari/537.36')
// .setViewport({width: 2485, height: 1380, scale: 1})
.goto('https://www.tradingview.com/')
.wait('.tv-header')
.wait(9000)
.evaluate(() => {
if (TradingView.isPro()) {
TradingView.signOut();
return false;
}
})
.wait(9000)
.wait('a.tv-header__link--signin')
.click('a.tv-header__link--signin')
.wait(1000)
.type('', 'input[name="username"]') // enter your TradingView.com user name here
.type('', 'input[name="password"]') // enter your TradingView.com password here
.wait(10000)
.click('button[type="submit"]')
.wait(6000)
.goto('https://www.tradingview.com/chart/')
.wait('.chart-markup-table', 30000)
.wait(7000)
.screenshot()
.catch((err) => {
console.error(err);
});
console.log(screenshot); // prints local file path or S3 url
}
}
require('make-runnable'); // must be at the END of the file
// Run directly from this script
// login().catch(console.error.bind(console));
// Run directly from this script
// module.exports.tradingViewLogin().catch(console.error.bind(console));
// Run directly from this script
// signout().catch(console.error.bind(console));
// This file automates logging into Autoview, useful if you have a lot of exchanges.
import { Chromeless } from 'chromeless';
declare var TradingView;
module.exports = {
autoviewSetup: async function () {
const chromeless = new Chromeless({
launchChrome: true,
waitTimeout: 20000
});
const kraken = await chromeless
.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3430.0 Safari/537.36')
// .setViewport({width: 2485, height: 1400, scale: 1})
.goto('chrome-extension://okdhadoplaoehmeldlpakhpekjcpljmb/options.html')
.wait(2000)
.click('[data-page="settings"]')
.wait(200)
.click('button[name="grant"][data-exchange="KRAKEN"]')
.wait(2000)
.click('[data-page="exchange-kraken"]')
.wait(200)
.type('', '#exchange-kraken-private-0') // private key
.type('', '#exchange-kraken-public-0') // public key
.click('button[name="test"][data-exchange="KRAKEN"]')
.wait(200)
.click('button[data-action="action_access_save"][data-exchange="KRAKEN"]')
.wait(5000)
.catch((err) => {
console.error(err);
});
console.log('Finished Enabling 1 Exchange! (Kraken)'); // prints local file path or S3 url
const bitfinex = await chromeless
.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3430.0 Safari/537.36')
// .setViewport({width: 2485, height: 1400, scale: 1})
.goto('chrome-extension://okdhadoplaoehmeldlpakhpekjcpljmb/options.html')
.wait(2000)
.click('[data-page="settings"]')
.wait(200)
.click('button[name="grant"][data-exchange="BITFINEX"]')
.wait(2000)
.click('[data-page="exchange-bitfinex"]')
.wait(200)
.type('', '#exchange-bitfinex-private-0') // private key
.type('', '#exchange-bitfinex-public-0') // public key
.click('button[name="test"][data-exchange="BITFINEX"]')
.wait(200)
.click('button[data-action="action_access_save"][data-exchange="BITFINEX"]')
.wait(5000)
.catch((err) => {
console.error(err);
});
console.log('Finished Enabling 1 Exchange! (Bitfinex)'); // prints local file path or S3 url
await chromeless.end();
}
}
// Make this runnable from package.json through NPM scripts using `make-runnable`
require('make-runnable'); // must be at the END of the file
.git
.idea
##########################################################
## These first commands are all run under the `root` user
##########################################################
## specify the node base image with your desired version node:<version>
FROM ubuntu:16.04
## Install latest chrome dev package.
## Note: this installs the necessary libs to make the bundled version of Chromium that Puppeteer installs, work. Also works for Chromeless, and Chrome in -headless mode.
RUN apt-get update && apt-get clean && apt-get install -y \
x11vnc \
xvfb \
fluxbox \
wmctrl \
wget \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list \
&& apt-get update && apt-get -y install google-chrome-stable \
&& apt-get -y autoclean
# Add additional dependencies here, to not invalidate the primary cache
RUN apt-get install -y nano \
curl
# Tini the "zombie reaper" is now available at /sbin/tini
# Whatever you put in the CMD [] section is what Tini will run as its default args
# Add Tini
ENV TINI_VERSION v0.16.1
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]
# Adds a user to the OS
RUN useradd node
# Replace shell with bash so we can source files
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
# NVM environment variables
ENV HOME=/home/node
ENV NVM_DIR=$HOME/.nvm
ENV NODE_VERSION 10.1.0
# Creates the dir including its "parents" -with p
RUN mkdir -p $HOME/.nvm
# Install nvm
# Install node and npm
# https://github.com/creationix/nvm#install-script
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash \
&& source $NVM_DIR/nvm.sh \
&& nvm install $NODE_VERSION \
&& nvm alias default $NODE_VERSION \
&& nvm use default
# Add node and npm to path so the commands are available
ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules
ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH
# Confirm installation
RUN node -v
RUN npm -v
# Install app dependencies
COPY . /home/node/app/
# Set NPM global install path into home directory so permissions are correct
RUN mkdir /home/node/.npm-global
RUN npm config set prefix "/home/node/.npm-global"
ENV PATH="/home/node/.npm-global/bin:${PATH}"
# Fix permissions so user Node can work with files
RUN chown -v -R node:node /home/node
#########################################################
# NOW, the following commands are run under the `node` user
#########################################################
# USER node MUST BE FIRST HERE!
USER node
# Install global packages, then local packages on frontend, then local packages on backend-nodejs, then build frontend, then build backend.
WORKDIR /home/node/app
# Run your program under Tini
# Starts the primary app - Virtual Display Manager
CMD './launch-virtual-display.sh
Copy the entire Autoview Extension into the /extension directory
// This is where the Docker Container will store the Chrome User Profile data, so it is persistent in case you need to restart the Docker Container or your Server