Skip to content
This repository has been archived by the owner on Aug 27, 2024. It is now read-only.

Commit

Permalink
add newpricepoint field
Browse files Browse the repository at this point in the history
remove base timestamp
  • Loading branch information
CelestialCrafter committed Dec 1, 2023
1 parent 7e03e2b commit 1d06e55
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 39 deletions.
2 changes: 2 additions & 0 deletions algorithms/bollinger_bands.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ def algorithm(prices, window_size=(20, 'days'), standard_deviations=2):

def signal(prices, data):
upper_band, middle_band, lower_band = data

if prices[-1] > upper_band[-1]:
return 'sell', 1
elif prices[-1] < lower_band[-1]:
return 'buy', 0.5

return 'no_action', 0
2 changes: 2 additions & 0 deletions algorithms/custom_bollinger_rsi.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ def signal(prices, data):

if price >= upper_band[-1] and rsi_line[-1] >= 70:
return 'sell', 1

return 'no_action', 0
3 changes: 3 additions & 0 deletions algorithms/rsi.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ def algorithm(prices, window_size=(14, 'days')):

def signal(prices, data, high=70, low=30):
rsi = data

if rsi[-1] > high:
strength = (rsi[-1] - high) * (1 / low)
return 'sell', strength

elif rsi[-1] < low:
strength = 1 - rsi[-1] * (1 / low)
return 'buy', strength

return 'no_action', 0
14 changes: 14 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import schedule, time
from threading import Thread
from dotenv import load_dotenv
from flask import Flask
from werkzeug.middleware.proxy_fix import ProxyFix
from price import update_cached_prices
from views import internal_checker, plot, worth, interval, update_interval

load_dotenv()
Expand All @@ -14,7 +17,18 @@
app.add_url_rule('/internal_checker', view_func=internal_checker.internal_checker)
app.add_url_rule('/update_interval', view_func=update_interval.update_interval, methods=['POST'])

def job_loop():
while True:
schedule.run_pending()
time.sleep(1)

if __name__ == '__main__':
schedule.every(2.5).minutes.do(update_cached_prices)
schedule.run_all()

thread = Thread(target=job_loop, daemon=True)
thread.start()

app.run()

def get_app():
Expand Down
38 changes: 13 additions & 25 deletions price.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import schedule, os, time
import os
import numpy as np
from math import ceil
from requests import get
from redis import from_url
from dotenv import load_dotenv
from threading import Thread
from flask import has_request_context, request

load_dotenv()
redis = from_url(os.environ['REDIS_URI'])

# 1 5 15 30 60 240 1440 10080 21600
# 12h 2d12h 1w12h 2w1d 1mo 4mo 2y 14y 30y
# 1 5 15 30 60 240 1440 10080 21600
# 12h 2d12h 1w12h 2w1d 1mo 4mo 2y 14y 30y

point_count = 720
default_interval = 240
Expand Down Expand Up @@ -41,23 +40,23 @@ def get_default_interval():
return int(interval)
return default_interval

def get_prices(pair='ETH/USD', interval='default', base_timestamp=None):
def get_prices(pair='ETH/USD', interval='default'):
if interval == 'default':
interval = get_default_interval()
if base_timestamp:
base_timestamp = int(base_timestamp)

ohlc = get(
f'https://api.kraken.com/0/public/OHLC?pair={pair}&interval={interval}{f"&since={base_timestamp}" if base_timestamp else ""}'
).json()
ohlc = get(f'https://api.kraken.com/0/public/OHLC?pair={pair}&interval={interval}').json()

if 'result' not in ohlc:
raise Exception(ohlc['error'][0])

timestamps = [point[0] for point in list(ohlc['result'].values())[0]]
prices = [float(point[4]) for point in list(ohlc['result'].values())[0]]
results = list(ohlc['result'].values())[0]

return np.array(prices).astype(float), np.array(timestamps).astype(float)
# [:-1] to trim off the uncomplete datapoint
timestamps = [point[0] for point in results][:-1]
prices = [float(point[4]) for point in results][:-1]
last_complete_point = ohlc['result']['last']

return np.array(prices).astype(float), np.array(timestamps).astype(float), last_complete_point

def get_cached_prices(interval='default'):
if interval == 'default':
Expand Down Expand Up @@ -102,20 +101,9 @@ def get_max_periods(interval='default'):
def update_cached_prices():
for interval in cached_intervals:
print(f'Caching prices for {interval}')
prices, timestamps = get_prices(interval=interval)
prices, timestamps, last_complete_point = get_prices(interval=interval)

redis.delete(f'prices:{interval}')
redis.delete(f'timestamps:{interval}')
redis.rpush(f'prices:{interval}', *prices.tolist())
redis.rpush(f'timestamps:{interval}', *timestamps.tolist())

schedule.every(3).minutes.do(update_cached_prices)

def job_loop():
schedule.run_all()
while True:
schedule.run_pending()
time.sleep(1)

thread = Thread(target=job_loop, daemon=True)
thread.start()
28 changes: 17 additions & 11 deletions views/internal_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
from redis import from_url
from price import get_prices
from ipaddress import ip_address
from flask import request
from flask import request, jsonify
from importlib import import_module
from utils import get_algorithms

redis = from_url(os.environ['REDIS_URI'])
last_checked_point = 0

def algorithm_output(algorithm, prices):
module = import_module(f'algorithms.{algorithm}')
Expand All @@ -15,6 +16,7 @@ def algorithm_output(algorithm, prices):
return algorithm, (signal, strength)

def internal_checker():
global last_checked_point
if not ip_address(request.remote_addr).is_private:
return 'Forbidden', 403

Expand All @@ -24,25 +26,29 @@ def internal_checker():

try:
jwt_decoded = jwt.decode(jwt_encoded, os.environ['JWT_SECRET'], algorithms=['HS256'])
except Exception as e:
print(e)
except Exception:
return 'Unauthorized', 401

if jwt_decoded['event'] != 'auth':
return 'Unauthorized', 401

prices = get_prices()
prices, timestamps, last_complete_point = get_prices()
new_datapoint = False
if last_complete_point > last_checked_point:
new_datapoint = True
last_checked_point = last_complete_point

# Convert list of algorithms into {name: signal}
algorithms = get_algorithms()

base = dict(map(lambda x: algorithm_output(*x), zip(algorithms, [prices] * len(algorithms))))
if new_datapoint:
base = dict(map(lambda x: algorithm_output(*x), zip(algorithms, [prices] * len(algorithms))))

signals = {k: v[0] for (k, v) in base.items()}
strengths = {k: v[1] for (k, v) in base.items()}
signals = {k: v[0] for (k, v) in base.items()}
strengths = {k: v[1] for (k, v) in base.items()}

redis.delete('signals', 'strengths')
redis.hset('signals', mapping=signals)
redis.hset('strengths', mapping=strengths)
redis.delete('signals', 'strengths')
redis.hset('signals', mapping=signals)
redis.hset('strengths', mapping=strengths)

return algorithms
return jsonify({'algorithms': algorithms, 'new_datapoint': new_datapoint})
6 changes: 3 additions & 3 deletions views/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ def plot(algorithm):
interval = int(request.args.get('interval'))

if interval and is_cached_interval(interval):
prices, timestamps = get_cached_prices(interval=interval)
prices, timestamps, _ = get_cached_prices(interval=interval)
elif interval and is_supported_interval(interval):
prices, timestamps = get_prices(interval=interval)
prices, timestamps, _ = get_prices(interval=interval)
elif not interval:
prices, timestamps = get_cached_prices()
prices, timestamps, _ = get_cached_prices()
else:
return 'Unsupported Interval', 400

Expand Down

0 comments on commit 1d06e55

Please sign in to comment.