Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Refactoring and new experimental behavior
========================================= * Our `/daemon` package renamed `daemonize.py`. easiest way to resolve conflict with `daemon` package. * `logger.py`: centralize logging logic. * `data.py` module containing new logic
- Loading branch information
Showing
with
143 additions
and 13 deletions.
- +0 −3 coincharts/daemon/__init__.py
- +3 −3 coincharts/{daemon/base.py → daemonize.py}
- +89 −0 coincharts/data.py
- +35 −6 coincharts/db.py
- +15 −0 coincharts/logger.py
- +1 −1 coincharts/models.py
@@ -0,0 +1,89 @@ | ||
# -*- mode: python; coding: utf-8 -*- | ||
|
||
import os | ||
os.environ['DJANGO_SETTINGS_MODULE'] = 'coincharts.settings' | ||
|
||
from mutils.memoize import memoize | ||
|
||
from coincharts.db import * | ||
|
||
from coincharts import config | ||
config = config.get_config() | ||
|
||
symbol_ids = config['history_symbols'] | ||
|
||
class SymbolIdInfo(object): | ||
|
||
def __init__(self, symbol_id): | ||
self.symbol_id = symbol_id | ||
|
||
def normalize_price(self, price): | ||
return (price - self.min) / (self.max - self.min) | ||
|
||
@property | ||
@memoize | ||
def date_range(self): | ||
start = self.history[0].time | ||
end = self.history[len(self.history)-1].time | ||
return start, end | ||
|
||
@property | ||
@memoize | ||
def min(self): | ||
return min([s.price for s in self.history]) | ||
|
||
@property | ||
@memoize | ||
def max(self): | ||
return max([s.price for s in self.history]) | ||
|
||
@property | ||
@memoize | ||
def history(self): | ||
return Prices.objects.filter(symbol_id=self.symbol_id) | ||
|
||
@property | ||
def normalized_price_history(self): | ||
price_delta = self.max - self.min | ||
for price in self.history: | ||
yield (price - self.min) / price_delta | ||
|
||
|
||
class SymbolIdComparison(dict): | ||
|
||
def __init__(self, *args, **kwargs): | ||
self.update(*args, **kwargs) | ||
self._start_date_indexes = {} | ||
self._earliest_common_time = None | ||
|
||
@property | ||
def start_date_indexes(self): | ||
if self._start_date_indexes is not None: | ||
return self._start_date_indexes | ||
for symbol_id, data in self.items(): | ||
try: | ||
self._start_date_indexes[symbol_id] = \ | ||
[s.date for s in data].index(self.earliest_common_time) | ||
except ValueError: | ||
raise ValueError('Could not find date {} in history of {}'.format( | ||
self.earliest_common_time, symbol_id)) | ||
|
||
@property | ||
def earliest_common_time(self): | ||
if self._earliest_common_time is not None: | ||
return self._earliest_common_time | ||
self._earliest_common_time = sorted([symbol[0].date for symbol in self.values()])[0] | ||
return self._earliest_common_time | ||
|
||
if __name__ == '__main__': | ||
|
||
symbol_id_info = SymbolIdComparison() | ||
for symbol_id in symbol_ids: | ||
symbol_id_info[symbol_id] = SymbolIdInfo(symbol_id) | ||
|
||
print('name\t\t\tmin\tmax\t\t\trange') | ||
for name, info in symbol_id_info.items(): | ||
print(name, | ||
info.min, | ||
info.max, '\t', | ||
info.date_range, sep='\t') |
@@ -1,19 +1,48 @@ | ||
# -*- mode: python; coding: utf-8 -*- | ||
"""re-export `modules.*` and make models (and ORM) usable outside of web framework. | ||
"""re-export `models.*` and make models (and ORM) usable outside of web framework. | ||
So, if you have django "app" `foo` installed as a package, from anywhere you should be able to | ||
>>> record = foo.db.SomeTable(**kwargs) | ||
>>> import db | ||
>>> record = db.SomeTable(**kwargs) | ||
>>> record.save() | ||
et cetera. | ||
""" | ||
|
||
import os | ||
import importlib | ||
import django | ||
from .settings import * | ||
|
||
from coincharts import logger | ||
|
||
# There is a bit of hackery here. Read comments starting with 'HACK' | ||
|
||
try: | ||
# HACK -- we require that DJANGO_SETTINGS_MODULE be set to the the name | ||
# of the site's settings' module, e.g. `mysite.settings` | ||
django_settings_module_name = os.environ['DJANGO_SETTINGS_MODULE'] | ||
except KeyError: | ||
raise ImportError(""" | ||
The "DJANGO_SETTINGS_MODULE" environment must be set to the name of your site's setting's module. For example: | ||
export DJANGO_SETTINGS_MODULE="mysite.settings" | ||
""") | ||
|
||
# HACK -- this is magic for "from mysite.settings import *" | ||
globals().update(importlib.import_module( | ||
django_settings_module_name).__dict__) | ||
|
||
from django.conf import settings | ||
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() | ||
|
||
from .models import * | ||
from coincharts.models import * | ||
|
||
def cleanup(): | ||
logger.info('closing all django database connections for this process') | ||
connections.close_all() | ||
|
||
atexit.register(cleanup) |
@@ -0,0 +1,15 @@ | ||
# -*- mode: python; coding: utf-8 -*- | ||
"""A small amount of justified magic: with this module, | ||
>>> import logger | ||
>>> logger.debug('yay!') | ||
""" | ||
|
||
import logging | ||
|
||
_logger = logging.getLogger(__name__) | ||
_logger.setLevel(logging.DEBUG) | ||
|
||
for level in 'debug', 'info', 'warning', 'error', 'exception', 'critical', 'addHandler': | ||
globals()[level] = getattr(_logger, level) | ||
|