Permalink
Browse files

Ability to graph "historical average"

-------------------------------------

* We're trying to do generators all the way down, so passing a `length` to some things
* Yielding `(dt.timestamp(), price)` since `svg_graph` currently needs a "numeral" for both X and Y
* Catching `RuntimeError` in `db.py` to avoid configuring django ORM twice. Is there a better way?
* Actually graphing historical average. Needs work but works!
* `to_xml` instead of relying on `__str__` in `LineGraph`. It's easy to accidentally exhaust the generator when debugging (e.g. `print("the graph looks like "+str(graph))`. Hard to diagnose. Instead we use an explicit method.
  • Loading branch information...
stnbu committed Sep 8, 2018
1 parent 92def93 commit 28bbb372af5f682184793c3d4e0974ba7fb6835e
Showing with 38 additions and 29 deletions.
  1. +16 −4 coincharts/data.py
  2. +7 −3 coincharts/db.py
  3. +1 −1 coincharts/urls.py
  4. +14 −21 coincharts/views.py
@@ -2,6 +2,7 @@
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'coincharts.settings'
from dateutil.parser import parse as parse_dt
from mutils.memoize import memoize
@@ -10,12 +11,12 @@
from coincharts import config
config = config.get_config()
symbols = config['history_symbols']
class SymbolInfo(object):
def __init__(self, symbol):
def __init__(self, symbol, length):
self.symbol = symbol
self.length = length # this is set below when we access the "history". Being as lazy as possible.
@property
@memoize
@@ -30,20 +31,30 @@ def max(self):
@property
@memoize
def history(self):
return Prices.objects.filter(symbol=self.symbol)
history = Prices.objects.filter(symbol=self.symbol)
self.length = len(history)
return history
@property
def normalized_history(self):
price_delta = self.max - self.min
for record in self.history:
yield record.dt, (record.price - self.min) / price_delta
yield parse_dt(record.dt).timestamp(), (record.price - self.min) / price_delta
class SymbolComparison(dict):
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs)
@property
def length(self):
# `self.length` has to be a calculated value, we may be truncating other symbol histories
# so we're only dealing with time periods where they all overlap (are present).
# So it's up to me* to set self.length as soon as practical.
# For now we'll just grab an arbitrary symbol and use its lenght attribute
return list(self.values())[0].length # <-- only a few symbols. not expensive.
def normalized_history_averages(self):
normalized_history_generators = []
for symbol, data in self.items():
@@ -67,6 +78,7 @@ def normalized_history_averages(self):
if __name__ == '__main__':
symbols = config['history_symbols']
comparison = SymbolComparison()
for symbol in symbols:
comparison[symbol] = SymbolInfo(symbol)
@@ -35,9 +35,13 @@
from django.db import connections
import atexit
# HACK -- note that the rhs "DATABASES" here comes from mysite.settings, above
settings.configure(DATABASES=DATABASES)
django.setup()
# HACK -- This is doubly a hack: "DATABASES" pops into existence (from .settings) and also we're using a kludgy try/except
# to test if the database is already configured.
try:
settings.configure(DATABASES=DATABASES)
django.setup()
except RuntimeError:
pass
from coincharts.models import *
@@ -3,5 +3,5 @@
from . import views
urlpatterns = [
path('<str:symbol>/', views.index, name='index'),
path('', views.index, name='index'),
]
@@ -6,37 +6,30 @@
from dateutil.parser import parse as parse_dt
import time
from coincharts import config
from coincharts.data import SymbolComparison, SymbolInfo
import svg_graph
def index(request, symbol):
prices = Prices.objects.filter(symbol=symbol)[:1000]
config = config.get_config()
def string_to_epoch(string):
return time.mktime(parse_dt(string).timetuple())
import svg_graph
def prices_gen(prices):
x = []
for p in prices:
x.append((p.dt, int(p.price)))
return x
def index(request):
title = '{} from {} to {}'.format(
symbol,
prices[0].dt,
prices[len(prices)-1].dt, # "negative indexing is not supported"
)
symbols = config['history_symbols']
comparison = SymbolComparison()
for symbol in symbols:
comparison[symbol] = SymbolInfo(symbol, length=967)
history_generator = comparison.normalized_history_averages()
graph = svg_graph.LineGraph(
title,
title='Price history averages',
height=580,
width=1200,
points=prices_gen(prices),
linear_x=True
points=history_generator,
length=comparison.length
)
context = {
'graph': graph,
'prices': prices,
'graph': graph.to_xml(),
}
return render(request, 'coincharts/index.html', context)

0 comments on commit 28bbb37

Please sign in to comment.