Introduce Order database model

This commit is contained in:
Matthias 2020-08-13 09:34:53 +02:00
parent 7d03a067ee
commit 171a52b21a
4 changed files with 74 additions and 6 deletions

View File

@ -487,6 +487,7 @@ class Exchange:
'side': side,
'remaining': _amount,
'datetime': arrow.utcnow().isoformat(),
'timestamp': arrow.utcnow().timestamp,
'status': "closed" if ordertype == "market" else "open",
'fee': None,
'info': {}

View File

@ -22,7 +22,7 @@ from freqtrade.exceptions import (DependencyException, ExchangeError,
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_next_date
from freqtrade.misc import safe_value_fallback, safe_value_fallback2
from freqtrade.pairlist.pairlistmanager import PairListManager
from freqtrade.persistence import Trade
from freqtrade.persistence import Order, Trade
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
from freqtrade.rpc import RPCManager, RPCMessageType
from freqtrade.state import State
@ -527,6 +527,7 @@ class FreqtradeBot:
order = self.exchange.buy(pair=pair, ordertype=order_type,
amount=amount, rate=buy_limit_requested,
time_in_force=time_in_force)
order_obj = Order.parse_from_ccxt_object(order, pair)
order_id = order['id']
order_status = order.get('status', None)
@ -580,6 +581,7 @@ class FreqtradeBot:
strategy=self.strategy.get_strategy_name(),
timeframe=timeframe_to_minutes(self.config['timeframe'])
)
trade.orders.append(order_obj)
# Update fees if order is closed
if order_status == 'closed':
@ -781,6 +783,9 @@ class FreqtradeBot:
stoploss_order = self.exchange.stoploss(pair=trade.pair, amount=trade.amount,
stop_price=stop_price,
order_types=self.strategy.order_types)
order_obj = Order.parse_from_ccxt_object(stoploss_order, trade.pair)
trade.orders.append(order_obj)
trade.stoploss_order_id = str(stoploss_order['id'])
return True
except InvalidOrderException as e:
@ -1123,12 +1128,15 @@ class FreqtradeBot:
return False
# Execute sell and update trade record
order = self.exchange.sell(pair=str(trade.pair),
order = self.exchange.sell(pair=trade.pair,
ordertype=order_type,
amount=amount, rate=limit,
time_in_force=time_in_force
)
order_obj = Order.parse_from_ccxt_object(order, trade.pair)
trade.orders.append(order_obj)
trade.open_order_id = order['id']
trade.close_rate_requested = limit
trade.sell_reason = sell_reason.value

View File

@ -1,3 +1,4 @@
# flake8: noqa: F401
from freqtrade.persistence.models import Trade, clean_dry_run_db, cleanup, init
from freqtrade.persistence.models import (Order, Trade, clean_dry_run_db,
cleanup, init)

View File

@ -7,11 +7,11 @@ from decimal import Decimal
from typing import Any, Dict, List, Optional
import arrow
from sqlalchemy import (Boolean, Column, DateTime, Float, Integer, String,
from sqlalchemy import (Boolean, Column, DateTime, Float, Integer, String, ForeignKey,
create_engine, desc, func)
from sqlalchemy.exc import NoSuchModuleError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Query
from sqlalchemy.orm import Query, relationship
from sqlalchemy.orm.scoping import scoped_session
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.pool import StaticPool
@ -85,13 +85,71 @@ def clean_dry_run_db() -> None:
trade.open_order_id = None
class Order(_DECL_BASE):
"""
Order database model
Keeps a record of all orders placed on the exchange
One to many relationship with Trades:
- One trade can have many orders
- One Order can only be associated with one Trade
Mirrors CCXT Order structure
"""
__tablename__ = 'orders'
id = Column(Integer, primary_key=True)
trade_id = Column(Integer, ForeignKey('trades.id'), index=True)
order_id = Column(String, nullable=False, index=True)
status = Column(String, nullable=False)
symbol = Column(String, nullable=False)
order_type = Column(String, nullable=False)
side = Column(String, nullable=False)
price = Column(Float, nullable=False)
amount = Column(Float, nullable=False)
filled = Column(Float, nullable=True)
remaining = Column(Float, nullable=True)
cost = Column(Float, nullable=True)
order_date = Column(DateTime, nullable=False, default=datetime.utcnow)
order_filled_date = Column(DateTime, nullable=True)
@staticmethod
def parse_from_ccxt_object(order, pair) -> 'Order':
"""
Parse an order from a ccxt object and return a new order Object.
"""
o = Order(order_id=str(order['id']))
o.status = order['status']
o.symbol = order.get('symbol', pair)
o.order_type = order['type']
o.side = order['side']
o.price = order['price']
o.amount = order['amount']
o.filled = order.get('filled')
o.remaining = order.get('remaining')
o.cost = order.get('cost')
o.order_date = datetime.fromtimestamp(order['timestamp'])
return o
def __repr__(self):
return (f'Order(id={self.id}, trade_id={self.trade_id}, side={self.side}, '
f'status={self.status})')
class Trade(_DECL_BASE):
"""
Class used to define a trade structure
Trade database model.
Also handles updating and querying trades
"""
__tablename__ = 'trades'
id = Column(Integer, primary_key=True)
orders = relationship("Order", order_by="Order.id")
exchange = Column(String, nullable=False)
pair = Column(String, nullable=False, index=True)
is_open = Column(Boolean, nullable=False, default=True, index=True)