From 80038b2c5ad2b8dc2ec27104c15f473af206fc0a Mon Sep 17 00:00:00 2001 From: Chris Lee Date: Sun, 31 Oct 2021 23:00:04 +1100 Subject: [PATCH 1/3] fix: refactor tradingview --- .../step/__tests__/get-trading-view.test.js | 20 +-- .../step/get-trading-view.js | 2 +- tradingview/Dockerfile | 3 + tradingview/README.md | 2 +- tradingview/main.py | 130 +++++++----------- tradingview/requirements.txt | 11 +- 6 files changed, 66 insertions(+), 102 deletions(-) diff --git a/app/cronjob/trailingTradeIndicator/step/__tests__/get-trading-view.test.js b/app/cronjob/trailingTradeIndicator/step/__tests__/get-trading-view.test.js index e7eec1ca..843dd5f0 100644 --- a/app/cronjob/trailingTradeIndicator/step/__tests__/get-trading-view.test.js +++ b/app/cronjob/trailingTradeIndicator/step/__tests__/get-trading-view.test.js @@ -104,7 +104,7 @@ describe('get-trading-view.js', () => { interval: '1h' }, paramsSerializer: expect.any(Function), - timeout: 5000 + timeout: 20000 } ); }); @@ -267,7 +267,7 @@ describe('get-trading-view.js', () => { interval: '15m' }, paramsSerializer: expect.any(Function), - timeout: 5000 + timeout: 20000 } ); @@ -280,7 +280,7 @@ describe('get-trading-view.js', () => { interval: '5m' }, paramsSerializer: expect.any(Function), - timeout: 5000 + timeout: 20000 } ); }); @@ -480,7 +480,7 @@ describe('get-trading-view.js', () => { interval: '15m' }, paramsSerializer: expect.any(Function), - timeout: 5000 + timeout: 20000 } ); @@ -493,7 +493,7 @@ describe('get-trading-view.js', () => { interval: '5m' }, paramsSerializer: expect.any(Function), - timeout: 5000 + timeout: 20000 } ); }); @@ -764,7 +764,7 @@ describe('get-trading-view.js', () => { interval: '15m' }, paramsSerializer: expect.any(Function), - timeout: 5000 + timeout: 20000 } ); @@ -777,7 +777,7 @@ describe('get-trading-view.js', () => { interval: '5m' }, paramsSerializer: expect.any(Function), - timeout: 5000 + timeout: 20000 } ); }); @@ -988,7 +988,7 @@ describe('get-trading-view.js', () => { interval: '1h' }, paramsSerializer: expect.any(Function), - timeout: 5000 + timeout: 20000 }); }); @@ -1072,7 +1072,7 @@ describe('get-trading-view.js', () => { interval: '1h' }, paramsSerializer: expect.any(Function), - timeout: 5000 + timeout: 20000 }); }); @@ -1138,7 +1138,7 @@ describe('get-trading-view.js', () => { interval: '1h' }, paramsSerializer: expect.any(Function), - timeout: 5000 + timeout: 20000 }); }); diff --git a/app/cronjob/trailingTradeIndicator/step/get-trading-view.js b/app/cronjob/trailingTradeIndicator/step/get-trading-view.js index ac957454..b4e10c85 100644 --- a/app/cronjob/trailingTradeIndicator/step/get-trading-view.js +++ b/app/cronjob/trailingTradeIndicator/step/get-trading-view.js @@ -39,7 +39,7 @@ const retrieveTradingView = async (logger, symbols, interval) => { paramsSerializer: /* istanbul ignore next */ p => qs.stringify(p, { arrayFormat: 'repeat' }), - timeout: 5000 // timeout 5 seconds + timeout: 20000 // timeout 20 seconds }); const tradingViewResult = _.get(response.data, 'result', {}); diff --git a/tradingview/Dockerfile b/tradingview/Dockerfile index 6f666ad4..f81c24df 100644 --- a/tradingview/Dockerfile +++ b/tradingview/Dockerfile @@ -9,6 +9,9 @@ RUN pip install -r requirements.txt COPY . . +ENV FLASK_APP=main.py +ENV FLASK_ENV=production + CMD [ "python", "main.py"] EXPOSE 8080 diff --git a/tradingview/README.md b/tradingview/README.md index b4ad5262..3b37a260 100644 --- a/tradingview/README.md +++ b/tradingview/README.md @@ -1,6 +1,6 @@ # TradingView Indicator -- Cloned from [https://github.com/reg2005/tradingview-ta-docker](https://github.com/reg2005/tradingview-ta-docker) +- Based on [https://github.com/reg2005/tradingview-ta-docker](https://github.com/reg2005/tradingview-ta-docker) - Based on [https://github.com/brian-the-dev/python-tradingview-ta](https://github.com/brian-the-dev/python-tradingview-ta) Since `tradingview-ta-docker` does not provide ARM docker image, I had to build in this project. diff --git a/tradingview/main.py b/tradingview/main.py index 7db4366b..1b0ae29b 100644 --- a/tradingview/main.py +++ b/tradingview/main.py @@ -1,89 +1,53 @@ -from http.server import BaseHTTPRequestHandler, HTTPServer -from tradingview_ta import TA_Handler, get_multiple_analysis -from urllib.parse import urlparse, parse_qs -import json - -hostName = "0.0.0.0" -serverPort = 8080 - - -class MyServer(BaseHTTPRequestHandler): - def _set_headers(self, statusCode): - self.send_response(statusCode) - self.send_header('Content-type', 'application/json') - self.end_headers() - - def _handle_symbol(self, qParsed): - print('Process _handle_symbol') - - symbol = qParsed['symbol'][0] - screener = qParsed['screener'][0] - exchange = qParsed['exchange'][0] - interval = qParsed['interval'][0] - tv = TA_Handler( - symbol=symbol, - screener=screener, - exchange=exchange, - interval=interval - ) - analyse = tv.get_analysis() - - print({symbol, screener, exchange, interval}, vars(analyse)) - self._set_headers(200) - self.wfile.write(bytes(json.dumps({'request': {'symbol': symbol, 'screener': screener, 'exchange': exchange, 'interval': interval}, 'result': { - 'summary': analyse.summary, 'time': analyse.time.isoformat(), 'oscillators': analyse.oscillators, 'moving_averages': analyse.moving_averages, 'indicators': analyse.indicators}}), "utf-8")) - - def _handle_symbols(self, qParsed): - print('Process _handle_symbols') - - symbols = qParsed['symbols'] - screener = qParsed['screener'][0] - interval = qParsed['interval'][0] - - analyse = get_multiple_analysis( - screener, interval, symbols - ) - - result = {} - for symbol in symbols: - symbolAnalyse = analyse[symbol] +import logging +import sys +import colorlog + +from flask import Flask, jsonify, request +from tradingview_ta import get_multiple_analysis + +app = Flask(__name__) + +logger = logging.getLogger('') +logger.setLevel(logging.DEBUG) +sh = logging.StreamHandler(sys.stdout) +sh.setFormatter(colorlog.ColoredFormatter( + '%(log_color)s [%(asctime)s] %(levelname)s [%(filename)s.%(funcName)s:%(lineno)d] %(message)s', datefmt='%a, %d %b %Y %H:%M:%S')) +logger.addHandler(sh) + + +@app.route('/', methods=['GET']) +def index(): + logger.info("Request: "+str(request.args)) + symbols = request.args.getlist('symbols') + screener = request.args.get('screener') + interval = request.args.get('interval') + + analyse = get_multiple_analysis( + screener, interval, symbols + ) + + result = {} + for symbol in symbols: + symbolAnalyse = analyse[symbol] + if not (symbolAnalyse is None): result[symbol] = { 'summary': symbolAnalyse.summary, 'time': symbolAnalyse.time.isoformat(), 'oscillators': symbolAnalyse.oscillators, 'moving_averages': symbolAnalyse.moving_averages, 'indicators': symbolAnalyse.indicators} - - print({tuple(symbols), screener, interval}, result) - - self._set_headers(200) - self.wfile.write(bytes(json.dumps({'request': { - 'symbols': symbols, 'screener': screener, 'interval': interval}, 'result': result}), "utf-8")) - - def do_HEAD(self): - self._set_headers() - - def do_GET(self): - o = urlparse(self.path) - qParsed = parse_qs(o.query) - - symbolExists = 'symbol' in qParsed - symbolsExists = 'symbols' in qParsed - - if symbolExists == True: - self._handle_symbol(qParsed) - elif symbolsExists == True: - self._handle_symbols(qParsed) else: - self._set_headers(500) - self.wfile.write(bytes(json.dumps( - {'request': qParsed, 'message': 'symbol or symbols must be provided.'}))) - + result[symbol] = {} + # logger.info('Processed '+symbol) -if __name__ == "__main__": - webServer = HTTPServer((hostName, serverPort), MyServer) - print("Server started http://%s:%s" % (hostName, serverPort)) + response = { + 'request': { + 'symbols': symbols, + 'screener': screener, + 'interval': interval + }, + 'result': result + } + logger.info("Response: "+str(response)) + return jsonify(response) - try: - webServer.serve_forever() - except KeyboardInterrupt: - pass - webServer.server_close() - print("Server stopped.") +if __name__ == "__main__": + from waitress import serve + serve(app, host="0.0.0.0", port=8080) diff --git a/tradingview/requirements.txt b/tradingview/requirements.txt index 8ed1def7..f1287c6e 100644 --- a/tradingview/requirements.txt +++ b/tradingview/requirements.txt @@ -1,9 +1,6 @@ -certifi==2021.10.8 -chardet==4.0.0 -idna==3.3 -protobuf==3.19.0 -pybind11==2.8.0 -requests==2.26.0 -six==1.16.0 tradingview-ta==3.2.9 +Flask==2.0.2 +waitress==2.0.0 urllib3==1.26.7 +paste==3.5.0 +colorlog==6.5.0 From 054f6b37ea34cb32581ad155b35bbcb6fdd5de74 Mon Sep 17 00:00:00 2001 From: Chris Lee Date: Sun, 31 Oct 2021 23:06:00 +1100 Subject: [PATCH 2/3] docs: updated CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5801abcd..97364b60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. +## [Unreleased] + +- Refactored TradingView python server - [#383](https://github.com/chrisleekr/binance-trading-bot/pull/383) + ## [0.0.84] - 2021-10-30 - Enhanced TradingView using get_multiple_analysis - [#375](https://github.com/chrisleekr/binance-trading-bot/pull/375) From b62200c2a47925cdc8648257ca5cfa47dcb6dbc4 Mon Sep 17 00:00:00 2001 From: Chris Lee Date: Sun, 31 Oct 2021 23:10:59 +1100 Subject: [PATCH 3/3] build: updated docker-compose files --- docker-compose.rpi.yml | 4 ++++ docker-compose.server.yml | 4 ++++ docker-compose.yml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/docker-compose.rpi.yml b/docker-compose.rpi.yml index d764f767..9bca657e 100644 --- a/docker-compose.rpi.yml +++ b/docker-compose.rpi.yml @@ -28,6 +28,10 @@ services: networks: - internal restart: unless-stopped + logging: + driver: 'json-file' + options: + max-size: '50m' binance-redis: container_name: binance-redis diff --git a/docker-compose.server.yml b/docker-compose.server.yml index 2ae550dc..47e9aa9c 100644 --- a/docker-compose.server.yml +++ b/docker-compose.server.yml @@ -28,6 +28,10 @@ services: networks: - internal restart: unless-stopped + logging: + driver: 'json-file' + options: + max-size: '50m' binance-redis: container_name: binance-redis diff --git a/docker-compose.yml b/docker-compose.yml index 91bc06f0..93ed49db 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -41,6 +41,10 @@ services: - PYTHONUNBUFFERED=1 ports: - 8082:8080 + logging: + driver: 'json-file' + options: + max-size: '50m' binance-redis: container_name: binance-redis