Rewrote OHLC into daily balances.
This commit is contained in:
parent
5d498adf32
commit
69d5f57b90
@ -166,8 +166,9 @@ class Operation(db.Model):
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
def get_ohlc_per_day_for_range(cls, account, begin=None, end=None):
|
||||
"""Get Opening, High, Low, Closing per day for a specific range"""
|
||||
def query_daily_balances(cls, account, begin=None, end=None):
|
||||
"""Get expenses, revenues, income and balance per day for a specific
|
||||
range and a specific account."""
|
||||
if isinstance(account, (int, str)):
|
||||
account_id = account
|
||||
else:
|
||||
@ -175,53 +176,65 @@ class Operation(db.Model):
|
||||
|
||||
end = end if end else arrow.now().ceil('month').date()
|
||||
|
||||
sold = db.func.sum(cls.value).over(
|
||||
order_by=[cls.operation_date, db.desc(cls.value), cls.label]
|
||||
)
|
||||
|
||||
previous = sold - cls.value
|
||||
|
||||
subquery = db.session.query(
|
||||
cls.operation_date,
|
||||
sold.label("sold"),
|
||||
previous.label("previous")
|
||||
).filter(
|
||||
cls.account_id == account_id,
|
||||
cls.canceled == db.false()
|
||||
).subquery()
|
||||
|
||||
query = db.session.query(
|
||||
subquery.c.operation_date,
|
||||
db.func.first_value(subquery.c.previous).over(
|
||||
partition_by=subquery.c.operation_date
|
||||
).label("open"),
|
||||
db.func.max(
|
||||
db.func.greatest(
|
||||
subquery.c.previous, subquery.c.sold
|
||||
cls.operation_date,
|
||||
db.func.coalesce(
|
||||
db.func.sum(
|
||||
cls.value
|
||||
).filter(
|
||||
db.func.sign(cls.value) == -1
|
||||
).over(
|
||||
partition_by=[cls.account_id, cls.operation_date],
|
||||
),
|
||||
0
|
||||
).label("expenses"),
|
||||
db.func.coalesce(
|
||||
db.func.sum(
|
||||
cls.value
|
||||
).filter(
|
||||
db.func.sign(cls.value) == 1
|
||||
).over(
|
||||
partition_by=[cls.account_id, cls.operation_date],
|
||||
),
|
||||
0
|
||||
).label("revenues"),
|
||||
db.func.coalesce(
|
||||
db.func.sum(
|
||||
cls.value
|
||||
).over(
|
||||
partition_by=[cls.account_id, cls.operation_date],
|
||||
)
|
||||
).over(
|
||||
partition_by=subquery.c.operation_date
|
||||
).label('high'),
|
||||
db.func.min(
|
||||
db.func.least(
|
||||
subquery.c.previous, subquery.c.sold
|
||||
).label("income"),
|
||||
db.func.coalesce(
|
||||
db.func.sum(
|
||||
cls.value
|
||||
).over(
|
||||
partition_by=cls.account_id,
|
||||
order_by=cls.operation_date
|
||||
)
|
||||
).over(
|
||||
partition_by=subquery.c.operation_date
|
||||
).label('low'),
|
||||
db.func.last_value(subquery.c.sold).over(
|
||||
partition_by=subquery.c.operation_date
|
||||
).label('close')
|
||||
).distinct()
|
||||
).label("balance")
|
||||
).distinct(
|
||||
).order_by(
|
||||
cls.operation_date
|
||||
).filter(
|
||||
cls.account_id == account_id
|
||||
)
|
||||
|
||||
if begin:
|
||||
query = query.filter(subquery.c.operation_date >= str(begin))
|
||||
base_query = query.subquery()
|
||||
|
||||
if end:
|
||||
query = query.filter(subquery.c.operation_date <= str(end))
|
||||
query = db.session.query(
|
||||
base_query
|
||||
).filter(
|
||||
base_query.c.operation_date >= str(begin)
|
||||
).order_by(
|
||||
base_query.c.operation_date
|
||||
)
|
||||
|
||||
query = query.order_by(
|
||||
subquery.c.operation_date
|
||||
)
|
||||
if end:
|
||||
query = query.filter(query.c.operation_date <= str(end))
|
||||
|
||||
elif end:
|
||||
query = query.filter(cls.operation_date <= str(end))
|
||||
|
||||
return query
|
||||
|
@ -7,7 +7,7 @@ import dateutil.parser
|
||||
from flask_jwt_extended import jwt_required
|
||||
from flask_restplus import Namespace, Resource, fields
|
||||
|
||||
from ..models import db, row_as_dict
|
||||
from ..models import db, row_as_dict, result_as_dicts
|
||||
from ..models.accounts import Account
|
||||
from ..models.operations import Operation
|
||||
|
||||
@ -71,33 +71,33 @@ category_model = ns.model('Category', {
|
||||
description='Total income for the category')
|
||||
})
|
||||
|
||||
# OHLC model.
|
||||
ohlc_model = ns.model('OHLC', {
|
||||
'operation_date': fields.DateTime(
|
||||
# Daily balance model.
|
||||
daily_balance_model = ns.model('Daily balance', {
|
||||
'operation_date': fields.Date(
|
||||
dt_format='iso8601',
|
||||
readonly=True,
|
||||
required=True,
|
||||
description='Date of the OHLC object'
|
||||
description='Date'
|
||||
),
|
||||
'open': fields.Float(
|
||||
'expenses': fields.Float(
|
||||
readonly=True,
|
||||
required=True,
|
||||
description='Open value'
|
||||
description='Expenses'
|
||||
),
|
||||
'high': fields.Float(
|
||||
'revenues': fields.Float(
|
||||
readonly=True,
|
||||
required=True,
|
||||
description='High value'
|
||||
description='Revenues'
|
||||
),
|
||||
'low': fields.Float(
|
||||
'income': fields.Float(
|
||||
readonly=True,
|
||||
required=True,
|
||||
description='Low value'
|
||||
description='Income'
|
||||
),
|
||||
'close': fields.Float(
|
||||
'balance': fields.Float(
|
||||
readonly=True,
|
||||
required=True,
|
||||
description='Close value'
|
||||
description='Balance'
|
||||
)
|
||||
})
|
||||
|
||||
@ -330,26 +330,29 @@ class CategoryResource(Resource):
|
||||
return Operation.get_categories_for_range(account_id, **data).all()
|
||||
|
||||
|
||||
@ns.route('/<int:account_id>/ohlc')
|
||||
@ns.route('/<int:account_id>/daily_balances')
|
||||
@ns.doc(
|
||||
security='apikey',
|
||||
params={
|
||||
'account_id': 'Id of the account to manage'
|
||||
},
|
||||
responses={
|
||||
200: ('OK', [ohlc_model]),
|
||||
200: ('OK', [daily_balance_model]),
|
||||
401: 'Unauthorized',
|
||||
404: 'Account not found'
|
||||
})
|
||||
class OHLCResource(Resource):
|
||||
"""Resource to expose OHLC."""
|
||||
class DailyBalancesResource(Resource):
|
||||
"""Resource to expose account daily balances."""
|
||||
|
||||
@ns.expect(range_parser)
|
||||
@ns.marshal_list_with(ohlc_model)
|
||||
@ns.marshal_list_with(daily_balance_model)
|
||||
@jwt_required
|
||||
def get(self, account_id):
|
||||
"""Get OHLC data for a specific date range and account."""
|
||||
"""Get account daily balance data for a specific date range and
|
||||
account."""
|
||||
|
||||
data = range_parser.parse_args()
|
||||
|
||||
return Operation.get_ohlc_per_day_for_range(account_id, **data).all()
|
||||
return list(result_as_dicts(
|
||||
Operation.query_daily_balances(account_id, **data)
|
||||
)), 200
|
||||
|
Loading…
Reference in New Issue
Block a user