diff --git a/core/lib/market.py b/core/lib/market.py index e804574..7c8da0e 100644 --- a/core/lib/market.py +++ b/core/lib/market.py @@ -24,10 +24,8 @@ def get_market_value(account, symbol): def execute_strategy(callback, strategy): - success, cash_balance = strategy.account.client.get_balance() + cash_balance = strategy.account.client.get_balance() log.debug(f"Cash balance: {cash_balance}") - if not success: - return None user = strategy.user account = strategy.account diff --git a/core/lib/schemas/__init__.py b/core/lib/schemas/__init__.py index e69de29..1cbcc04 100644 --- a/core/lib/schemas/__init__.py +++ b/core/lib/schemas/__init__.py @@ -0,0 +1 @@ +from core.lib.schemas import alpaca_s, drakdoo_s, oanda_s # noqa diff --git a/core/lib/trades.py b/core/lib/trades.py deleted file mode 100644 index 6651e9f..0000000 --- a/core/lib/trades.py +++ /dev/null @@ -1,82 +0,0 @@ -# Trade handling -from alpaca.common.exceptions import APIError -from alpaca.trading.enums import OrderSide, TimeInForce -from alpaca.trading.requests import LimitOrderRequest, MarketOrderRequest - -from core.util import logs - -log = logs.get_logger(__name__) - - -def sync_trades_with_db(user): - pass - - -def post_trade(trade): - # the trade is not placed yet - trading_client = trade.account.get_client() - if trade.direction == "buy": - direction = OrderSide.BUY - elif trade.direction == "sell": - direction = OrderSide.SELL - else: - raise Exception("Unknown direction") - - cast = {"symbol": trade.symbol, "side": direction, "time_in_force": TimeInForce.IOC} - if trade.amount is not None: - cast["qty"] = trade.amount - if trade.amount_usd is not None: - cast["notional"] = trade.amount_usd - if not trade.amount and not trade.amount_usd: - return (False, "No amount specified") - if trade.take_profit: - cast["take_profit"] = {"limit_price": trade.take_profit} - if trade.stop_loss: - stop_limit_price = trade.stop_loss - (trade.stop_loss * 0.005) - cast["stop_loss"] = { - "stop_price": trade.stop_loss, - "limit_price": stop_limit_price, - } - if trade.type == "market": - market_order_data = MarketOrderRequest(**cast) - try: - order = trading_client.submit_order(order_data=market_order_data) - except APIError as e: - log.error(f"Error placing market order: {e}") - return (False, e) - elif trade.type == "limit": - if not trade.price: - return (False, "Limit order with no price") - cast["limit_price"] = trade.price - limit_order_data = LimitOrderRequest(**cast) - try: - order = trading_client.submit_order(order_data=limit_order_data) - except APIError as e: - log.error(f"Error placing limit order: {e}") - return (False, e) - - else: - raise Exception("Unknown trade type") - trade.response = order - trade.status = "posted" - trade.order_id = order["id"] - trade.client_order_id = order["client_order_id"] - trade.save() - return (True, order) - - -def update_trade(self): - pass - - -def close_trade(trade): - pass - - -def get_position_info(account, symbol): - trading_client = account.get_client() - try: - position = trading_client.get_open_position(symbol) - except APIError as e: - return (False, e) - return (True, position) diff --git a/core/models.py b/core/models.py index da55226..2765c17 100644 --- a/core/models.py +++ b/core/models.py @@ -90,9 +90,8 @@ class Account(models.Model): """ client = self.get_client() if client: - success, supported_symbols = client.get_supported_assets() - if success: - self.supported_symbols = supported_symbols + supported_symbols = client.get_supported_assets() + self.supported_symbols = supported_symbols super().save(*args, **kwargs) def get_client(self): diff --git a/core/views/__init__.py b/core/views/__init__.py index a2c2fa5..e15a380 100644 --- a/core/views/__init__.py +++ b/core/views/__init__.py @@ -12,20 +12,23 @@ from core.util import logs log = logs.get_logger(__name__) -class ObjectList(ListView): +class ObjectNameMixin(object): + def __init__(self, *args, **kwargs): + self.title_singular = self.model._meta.verbose_name.title() # Hook + self.context_object_name_singular = self.title_singular.lower() # hook + self.title = self.model._meta.verbose_name_plural.title() # Hooks + self.context_object_name = self.title.lower() # hooks + super().__init__(*args, **kwargs) + + +class ObjectList(ObjectNameMixin, ListView): allowed_types = ["modal", "widget", "window", "page"] window_content = "window-content/objects.html" list_template = None - model = None - context_object_name = "objects" - context_object_name_singular = "object" page_title = None page_subtitle = None - title = "Objects" - title_singular = "Object" - list_url_name = None # WARNING: TAKEN FROM locals() list_url_args = ["type"] @@ -91,13 +94,12 @@ class ObjectList(ListView): return self.render_to_response(context) -class ObjectCreate(CreateView): +class ObjectCreate(ObjectNameMixin, CreateView): allowed_types = ["modal", "widget", "window", "page"] window_content = "window-content/object-form.html" parser_classes = [FormParser] model = None - context_object_name = "objects" submit_url_name = None list_url_name = None @@ -159,21 +161,19 @@ class ObjectCreate(CreateView): return super().post(request, *args, **kwargs) -class ObjectRead(DetailView): +class ObjectRead(ObjectNameMixin, DetailView): allowed_types = ["modal", "widget", "window", "page"] window_content = "window-content/object.html" model = None - context_object_name = "object" -class ObjectUpdate(UpdateView): +class ObjectUpdate(ObjectNameMixin, UpdateView): allowed_types = ["modal", "widget", "window", "page"] window_content = "window-content/object-form.html" parser_classes = [FormParser] model = None - context_object_name = "objects" submit_url_name = None request = None @@ -225,9 +225,8 @@ class ObjectUpdate(UpdateView): return super().post(request, *args, **kwargs) -class ObjectDelete(DeleteView): +class ObjectDelete(ObjectNameMixin, DeleteView): model = None - context_object_name_singular = "object" template_name = "partials/notify.html" # Overriden to prevent success URL from being used diff --git a/core/views/accounts.py b/core/views/accounts.py index d651596..2bdf6ab 100644 --- a/core/views/accounts.py +++ b/core/views/accounts.py @@ -39,14 +39,7 @@ class AccountInfo(LoginRequiredMixin, View): } return render(request, template_name, context) - success, live_info = account.client.get_account() - if not success: - context = { - "message": "Could not get account info", - "class": "danger", - "window_content": self.window_content, - } - return render(request, template_name, context) + live_info = account.client.get_account() live_info = live_info account_info = account.__dict__ account_info = { @@ -70,10 +63,6 @@ class AccountInfo(LoginRequiredMixin, View): class AccountList(LoginRequiredMixin, ObjectList): list_template = "partials/account-list.html" model = Account - context_object_name = "accounts" - context_object_name_singular = "account" - title = "Accounts" - title_singular = "Account" page_title = "List of accounts" list_url_name = "accounts" @@ -85,8 +74,6 @@ class AccountList(LoginRequiredMixin, ObjectList): class AccountCreate(LoginRequiredMixin, ObjectCreate): model = Account form_class = AccountForm - context_object_name = "accounts" - context_object_name_singular = "account" list_url_name = "accounts" list_url_args = ["type"] @@ -110,8 +97,6 @@ class AccountCreate(LoginRequiredMixin, ObjectCreate): class AccountUpdate(LoginRequiredMixin, ObjectUpdate): model = Account form_class = AccountForm - context_object_name = "accounts" - context_object_name_singular = "account" list_url_name = "accounts" list_url_args = ["type"] @@ -121,8 +106,6 @@ class AccountUpdate(LoginRequiredMixin, ObjectUpdate): class AccountDelete(LoginRequiredMixin, ObjectDelete): model = Account - context_object_name = "accounts" - context_object_name_singular = "account" list_url_name = "accounts" list_url_args = ["type"] diff --git a/core/views/hooks.py b/core/views/hooks.py index 37a162d..43d6bd4 100644 --- a/core/views/hooks.py +++ b/core/views/hooks.py @@ -106,10 +106,6 @@ class HookList(LoginRequiredMixin, ObjectList): # window_content = "window-content/hooks.html" list_template = "partials/hook-list.html" model = Hook - context_object_name = "hooks" - context_object_name_singular = "hook" - title = "Hooks" - title_singular = "Hook" page_title = "List of active URL endpoints for receiving hooks." page_subtitle = ( "Add URLs here to receive Drakdoo callbacks. " @@ -125,8 +121,6 @@ class HookList(LoginRequiredMixin, ObjectList): class HookCreate(LoginRequiredMixin, ObjectCreate): model = Hook form_class = HookForm - context_object_name = "hooks" - context_object_name_singular = "hook" list_url_name = "hooks" list_url_args = ["type"] @@ -137,8 +131,6 @@ class HookCreate(LoginRequiredMixin, ObjectCreate): class HookUpdate(LoginRequiredMixin, ObjectUpdate): model = Hook form_class = HookForm - context_object_name = "hooks" - context_object_name_singular = "hook" list_url_name = "hooks" list_url_args = ["type"] @@ -148,8 +140,6 @@ class HookUpdate(LoginRequiredMixin, ObjectUpdate): class HookDelete(LoginRequiredMixin, ObjectDelete): model = Hook - context_object_name = "hooks" - context_object_name_singular = "hook" list_url_name = "hooks" list_url_args = ["type"] diff --git a/core/views/positions.py b/core/views/positions.py index b781aad..b47b6b9 100644 --- a/core/views/positions.py +++ b/core/views/positions.py @@ -70,16 +70,14 @@ class PositionAction(LoginRequiredMixin, View): info = account.client.get_position_info(symbol) print("ACCT INFO", info) - items = get_positions(request.user, account_id) if type == "page": type = "modal" context = { "title": f"Hooks ({type})", "unique": unique, "window_content": self.window_content, - "items": items, "type": type, + "items": info, } - context["items"] = info return render(request, template_name, context) diff --git a/core/views/strategies.py b/core/views/strategies.py index e844d6e..e62b87c 100644 --- a/core/views/strategies.py +++ b/core/views/strategies.py @@ -14,10 +14,6 @@ log = logs.get_logger(__name__) class StrategyList(LoginRequiredMixin, ObjectList): list_template = "partials/strategy-list.html" model = Strategy - context_object_name = "strategies" - context_object_name_singular = "strategy" - title = "Strategies" - title_singular = "Strategy" page_title = "List of strategies" list_url_name = "strategies" @@ -29,9 +25,6 @@ class StrategyList(LoginRequiredMixin, ObjectList): class StrategyCreate(LoginRequiredMixin, ObjectCreate): model = Strategy form_class = StrategyForm - context_object_name = "strategies" - context_object_name_singular = "strategy" - list_url_name = "strategies" list_url_args = ["type"] @@ -41,8 +34,6 @@ class StrategyCreate(LoginRequiredMixin, ObjectCreate): class StrategyUpdate(LoginRequiredMixin, ObjectUpdate): model = Strategy form_class = StrategyForm - context_object_name = "strategies" - context_object_name_singular = "strategy" list_url_name = "strategies" list_url_args = ["type"] @@ -52,8 +43,6 @@ class StrategyUpdate(LoginRequiredMixin, ObjectUpdate): class StrategyDelete(LoginRequiredMixin, ObjectDelete): model = Strategy - context_object_name = "strategies" - context_object_name_singular = "strategy" list_url_name = "strategies" list_url_args = ["type"] diff --git a/core/views/trades.py b/core/views/trades.py index c2165e1..1f0130c 100644 --- a/core/views/trades.py +++ b/core/views/trades.py @@ -5,7 +5,13 @@ from django.views import View from core.forms import TradeForm from core.models import Trade from core.util import logs -from core.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate +from core.views import ( + ObjectCreate, + ObjectDelete, + ObjectList, + ObjectNameMixin, + ObjectUpdate, +) log = logs.get_logger(__name__) @@ -13,10 +19,6 @@ log = logs.get_logger(__name__) class TradeList(LoginRequiredMixin, ObjectList): list_template = "partials/trade-list.html" model = Trade - context_object_name = "trades" - context_object_name_singular = "trade" - title = "Trades" - title_singular = "Trade" page_title = ( "List of bot and manual trades. This may not reflect actual live trades." ) @@ -33,9 +35,6 @@ class TradeList(LoginRequiredMixin, ObjectList): class TradeCreate(LoginRequiredMixin, ObjectCreate): model = Trade form_class = TradeForm - context_object_name = "trades" - context_object_name_singular = "trade" - list_url_name = "trades" list_url_args = ["type"] @@ -49,9 +48,6 @@ class TradeCreate(LoginRequiredMixin, ObjectCreate): class TradeUpdate(LoginRequiredMixin, ObjectUpdate): model = Trade form_class = TradeForm - context_object_name = "trades" - context_object_name_singular = "trade" - list_url_name = "trades" list_url_args = ["type"] @@ -60,15 +56,14 @@ class TradeUpdate(LoginRequiredMixin, ObjectUpdate): class TradeDelete(LoginRequiredMixin, ObjectDelete): model = Trade - context_object_name = "trades" - context_object_name_singular = "trade" list_url_name = "trades" list_url_args = ["type"] -class TradeDeleteAll(LoginRequiredMixin, View): +class TradeDeleteAll(LoginRequiredMixin, ObjectNameMixin, View): template_name = "partials/notify.html" + model = Trade def delete(self, request): """