def resolve_performances(self, info, provider_id, account_id=None, **kwargs): provider = info.context.user.service_providers.get(id=provider_id) account = info.context.user.accounts.get( id=account_id) if account_id else None account_key = account.account_key.strip() if account \ else provider.account_key.strip() if not account_key: raise AttributeError( 'Account Key not provided. ' + 'Either specify accountId argument or configure a default accountKey on the provider.' ) etrade = get_provider_instance(provider) transactions = etrade.get_transactions(account_key) or [] symbol_map = {} for tran in transactions: brokerage = tran.get("brokerage") product = brokerage.get("product") transaction_type = tran.get("transactionType") transaction_date = tran.get("transactionDate") symbol = product.get("symbol") quantity = brokerage.get("quantity") amount = tran.get("amount") if transaction_type not in ('Bought', 'Sold'): continue if symbol not in symbol_map: performance = { 'symbol': symbol, 'amount': Decimal(amount), 'date': datetime.datetime.fromtimestamp(transaction_date/1000), 'bought': int(quantity) if transaction_type == 'Bought' else 0, 'sold': int(quantity) * -1 if transaction_type == 'Sold' else 0 } symbol_map[symbol] = performance else: performace = symbol_map[symbol] performace['date'] = datetime.datetime.fromtimestamp( transaction_date/1000) performace['amount'] = performace['amount'] + \ Decimal(amount) if transaction_type == 'Bought': performace['bought'] = performace['bought'] + \ int(quantity) else: performace['sold'] = performace['sold'] + \ int(quantity) * -1 performances = [val for val in symbol_map.values() if val['bought'] == val['sold']] performances.sort(key=lambda val: val['date'], reverse=True) return performances
def mutate_and_get_payload(cls, root, info, symbol, provider_id, account_id=None): account = Account.objects.get(id=account_id) if account_id else None provider = ServiceProvider.objects.select_related('session') \ .get(id=provider_id) account_key = account.account_key.strip() if account \ else provider.account_key.strip() if not account_key: return StopLoss( error=StopLossError.ACCOUNT_NOT_PROVIDED, error_message= 'Either specify an accountId that has a valid accountKey ' + 'or configure a default accountKey on the provider.') autopilot = get_autopilot(info.context.user.id, symbol) if autopilot: return StopLoss(error=StopLossError.NOT_ALLOWED_ON_AUTOPILOT, error_message='You must turn off autopilot first.') etrade = get_provider_instance(provider) position_quantity = etrade.get_position_quantity(account_key, symbol) quote = etrade.get_quote(symbol) last_price = get_bid(quote) stop_price = get_round_price(last_price - (last_price * Decimal('0.02'))) limit_price = get_limit_price(OrderAction.SELL, stop_price, margin=Decimal('0.02')) order_params = { 'account_key': account_key, 'market_session': MarketSession.current().value, 'action': OrderAction.SELL.value, 'symbol': symbol, 'price_type': PriceType.STOP_LIMIT.value, 'quantity': position_quantity, 'stop_price': stop_price, 'limit_price': limit_price } preview_ids = etrade.preview_order( order_client_id=get_random_string(length=20), **order_params) etrade.place_order(order_client_id=get_random_string(length=20), preview_ids=preview_ids, **order_params) return StopLoss()
def resolve_session_status(self, *args, **kwargs): session = ProviderSession.objects.filter(provider=self).first() if not session: return ProviderSession.CLOSED etrade = get_provider_instance(self) if self.session and not etrade.is_session_active(): self.session.delete() self.session = None self.save() return ProviderSession.CLOSED return self.session.status
def resolve_transactions(self, info, provider_id, account_id=None, **kwargs): provider = info.context.user.service_providers.get(id=provider_id) account = info.context.user.accounts.get( id=account_id) if account_id else None account_key = account.account_key.strip() if account \ else provider.account_key.strip() if not account_key: raise AttributeError( 'Account Key not provided. ' + 'Either specify accountId argument or configure a default accountKey on the provider.' ) etrade = get_provider_instance(provider) return etrade.get_transactions(account_key) or []
def mutate_and_get_payload(cls, root, info, provider_id): provider = info.context.user.service_providers.filter( id=provider_id).first() if not provider: return ConnectProvider( error=ConnectProviderError.PROVIDER_NOT_FOUND, error_message= "Sorry! the provider you're trying to connect to was not found." ) etrade = get_provider_instance(provider) authorize_url = etrade.get_authorize_url() return ConnectProvider(service_provider=provider, authorize_url=authorize_url, callback_enabled=provider.callback_configured)
def resolve_quote(self, info, symbol): etrade = get_provider_instance(self) quote_data = etrade.get_quote(symbol) if not quote_data: return None return QuoteType( volume=get_volume(quote_data), last=get_last(quote_data), bid=get_bid(quote_data), ask=get_ask(quote_data), last_trade_direction=Decimal( str(quote_data.get('All').get('dirLast'))), market_cap=Decimal(str(quote_data.get('All').get('marketCap'))), shares_outstanding=quote_data.get('All').get('sharesOutstanding'), primary_exchange=quote_data.get('All').get('primaryExchange'), company_name=quote_data.get('All').get('companyName'), )
def mutate_and_get_payload(cls, root, info, oauth_verifier, oauth_token=None, provider_id=None): if not oauth_token and not provider_id: return AuthorizeConnection( error=AuthorizeConnectionError.MISSING_REQUIRED_FIELD, error_message="Provide oath_token or provider_id") if oauth_token: provider = info.context.user.service_providers \ .filter(session__request_token=oauth_token) \ .select_related('session') \ .first() else: provider = info.context.user.service_providers \ .filter(id=provider_id) \ .select_related('session') \ .first() if not provider: return AuthorizeConnection( error=AuthorizeConnectionError.SESSION_NOT_FOUND, error_message= "Pending session not found. Try starting a new connection.") if provider.session.status != ProviderSession.REQUESTING: return AuthorizeConnection( error=AuthorizeConnectionError.INCOMPATIBLE_STATE, error_message= "Session state is not compatible. Try starting a new connection." ) etrade = get_provider_instance(provider) provider = etrade.authorize(oauth_verifier) return AuthorizeConnection(service_provider=provider)
def mutate_and_get_payload(cls, root, info, order_id, provider_id, account_id=None): account = Account.objects.get(id=account_id) if account_id else None provider = ServiceProvider.objects.select_related('session') \ .get(id=provider_id) account_key = account.account_key.strip() if account \ else provider.account_key.strip() if not account_key: return CancelOrder( error=CancelOrderError.ACCOUNT_NOT_PROVIDED, error_message= 'Either specify an accountId that has a valid accountKey ' + 'or configure a default accountKey on the provider.') etrade = get_provider_instance(provider) etrade.cancel_order(account_key=account_key, order_id=order_id) return CancelOrder()
def mutate_and_get_payload(cls, root, info, provider_id): provider = info.context.user.service_providers \ .filter(id=provider_id) \ .select_related('session') \ .first() if not provider: return AuthorizeConnection( error=SyncAccounts.PROVIDER_NOT_FOUND, error_message= "Pending session not found. Try starting a new connection.") etrade = get_provider_instance(provider) etrade.sync_accounts() default_account = Account.objects.filter( institution_type='BROKERAGE').first() if not provider.account_key: provider.account_key = default_account.account_key provider.save() return SyncAccounts(broker=provider.broker)
def oauth1_verify(request: Request): data = request.data oauth_token = data.get("oauthToken", None) oauth_verifier = data.get("oauthVerifier", None) if not oauth_token: return Response({ "error": f'oauthToken required' }) provider = ServiceProvider.objects \ .filter(session__request_token=oauth_token) \ .select_related('session', 'broker', 'user__auth_token') \ .first() if not provider: return Response({ "error": f'no session found for provided oauthToken' }) etrade = get_provider_instance(provider) try: provider = etrade.authorize(oauth_verifier) except KeyError as e: if f'Token {oauth_token} is invalid, or has expired' in str(e): return Response({ "error": f'Token expired.' }) else: raise return Response({ "accessToken": provider.user.auth_token.key, "brokerSlug": provider.broker.slug, "providerSlug": provider.slug, })
def mutate_and_get_payload(cls, root, info, symbol, strategy_id=None, provider_id=None, account_id=None, modifier=None): user = info.context.user strategy = user.trading_strategies.get( id=strategy_id) if strategy_id else cls.get_default_strategy(info) if not strategy: return AutoPilotON( error=AutoPilotONError.STRATEGY_REQUIRED, error_message= 'Either set the strategy_id param or configure a default.') provider = user.service_providers.get( id=provider_id) if provider_id else cls.get_default_privider(info) if not provider: return AutoPilotON( error=AutoPilotONError.PROVIDER_REQUIRED, error_message= 'Either set the provider_id param or configure a default.') account = user.accounts.get( id=account_id) if account_id else cls.get_default_account(info) if not account: return AutoPilotON( error=AutoPilotONError.ACCOUNT_REQUIRED, error_message= 'Either set the account_id param or configure a default.') if AutoPilotTask.objects.filter(symbol=symbol, status=AutoPilotTask.RUNNING).exists(): return AutoPilotON( error=AutoPilotONError.ALREADY_EXISTS, error_message=f'Autopilot for {symbol} already exists.') if modifier is None: modifier = cls.get_default_modifier(user) discord_webhook = cls.get_discord_webhook(info) etrade = get_provider_instance(provider) quantity, entry_price = etrade.get_position(account.account_key, symbol) if not quantity or not entry_price: return AutoPilotON( error=AutoPilotONError.NO_POSITION_FOR_SYMBOL, error_message= f'No position found for {symbol}. Position: {quantity}@{entry_price}' ) quote = etrade.get_quote(symbol) is_otc = etrade.is_otc(quote) task = AutoPilotTask(user=user, strategy=strategy, provider=provider, account=account, is_otc=is_otc, symbol=symbol, quantity=quantity, entry_price=entry_price, base_price=entry_price, loss_ref_price=entry_price, profit_ref_price=entry_price, ref_time=timezone.now(), modifier=modifier, discord_webhook=discord_webhook) task.save() return AutoPilotON()
def mutate_and_get_payload(cls, root, info, symbol, provider_id, strategy_id=None, account_id=None): account = Account.objects.get(id=account_id) if account_id else None provider = ServiceProvider.objects.select_related('session') \ .get(id=provider_id) strategy = None if strategy_id: strategy = info.context.user.trading_strategies.filter( id=strategy_id).first() if not strategy: return StopProfit( error=StopProfitError.STRATEGY_NOT_FOUND, error_message= f'TradingStrategy with id {strategy_id} not found.') account_key = account.account_key.strip() if account \ else provider.account_key.strip() if not account_key: return StopProfit( error=StopProfitError.ACCOUNT_NOT_PROVIDED, error_message= 'Either specify an accountId that has a valid accountKey ' + 'or configure a default accountKey on the provider.') autopilot = get_autopilot(info.context.user.id, symbol) if autopilot: return StopProfit( error=StopProfitError.NOT_ALLOWED_ON_AUTOPILOT, error_message='You must turn off autopilot first.') etrade = get_provider_instance(provider) position_quantity, entry_price = etrade.get_position( account_key, symbol) if strategy: profit_amount = entry_price * (strategy.profit_percent / 100) stop_price = get_round_price(entry_price + profit_amount) else: quote = etrade.get_quote(symbol) last_price = get_ask(quote) profit_amount = last_price * Decimal('0.02') stop_price = get_round_price(last_price + profit_amount) limit_price = get_limit_price(OrderAction.SELL, stop_price, margin=Decimal('0.01')) order_params = { 'account_key': account_key, 'market_session': MarketSession.current().value, 'action': OrderAction.SELL.value, 'symbol': symbol, 'price_type': PriceType.STOP_LIMIT.value, 'quantity': position_quantity, 'stop_price': stop_price, 'limit_price': limit_price } preview_ids = etrade.preview_order( order_client_id=get_random_string(length=20), **order_params) etrade.place_order(order_client_id=get_random_string(length=20), preview_ids=preview_ids, **order_params) return StopProfit()
def mutate_and_get_payload(cls, root, info, symbol, provider_id, margin='0.00', price='0.0000', quantity=0, account_id=None): account = Account.objects.get(id=account_id) if account_id else None provider = ServiceProvider.objects.select_related('session') \ .get(id=provider_id) account_key = account.account_key.strip() if account \ else provider.account_key.strip() if not account_key: return SellStock( error=SellStockError.ACCOUNT_NOT_PROVIDED, error_message= 'Either specify an accountId that has a valid accountKey ' + 'or configure a default accountKey on the provider.') # turn_off_autopilot(info.context.user.id, symbol) autopilot = get_autopilot(info.context.user.id, symbol) if autopilot: autopilot.signal = AutoPilotTask.SELL autopilot.save() return SellStock() etrade = get_provider_instance(provider) if Decimal(price): limit_price = Decimal(price).quantize(Decimal('0.0001')) else: quantized_margin = Decimal(margin).quantize(Decimal('0.001')) print(f'margin: {Decimal(quantized_margin)}') quote = etrade.get_quote(symbol) limit_price = get_limit_price(OrderAction.SELL, get_ask(quote), margin=Decimal(quantized_margin) or Decimal('0.1')) if not quantity: quantity = etrade.get_position_quantity(account_key, symbol) order_params = { 'account_key': account_key, 'market_session': MarketSession.current().value, 'action': OrderAction.SELL.value, 'symbol': symbol, 'price_type': PriceType.LIMIT.value, 'quantity': quantity, 'limit_price': limit_price } preview_ids = etrade.preview_order( order_client_id=get_random_string(length=20), **order_params) etrade.place_order(order_client_id=get_random_string(length=20), preview_ids=preview_ids, **order_params) return SellStock()
def mutate_and_get_payload(cls, root, info, symbol, strategy_id, provider_id, margin='0.00', price='0.0000', quantity=0, account_id=None, autopilot=False): strategy = TradingStrategy.objects.get(id=strategy_id) provider = ServiceProvider.objects.select_related('session') \ .get(id=provider_id) account = Account.objects.get(id=account_id) if account_id else None account_key = account.account_key.strip() if account \ else provider.account_key.strip() if not account_key: return BuyStock( error=BuyStockError.ACCOUNT_NOT_PROVIDED, error_message= 'Either specify an accountId that has a valid accountKey ' + 'or configure a default accountKey on the provider.') if not account: account = Account.objects.get(account_key=account_key) if not strategy.funded(account): return BuyStock( error=BuyStockError.INSUFFICIENT_FUNDS, error_message='Insufficient funds. Strategy selected ' + 'requires more cash available for investment.') etrade = get_provider_instance(provider) if autopilot: quote = etrade.get_quote(symbol) is_otc = etrade.is_otc(quote) user = info.context.user settings = Settings.objects.filter(user_id=user.id).first() default_modifier = settings.default_autopilot_modifier if settings else None discord_webhook = settings.discord_webhook if settings else None task = AutoPilotTask(signal=AutoPilotTask.BUY, user=info.context.user, strategy=strategy, provider=provider, account=account, is_otc=is_otc, symbol=symbol, quantity=quantity, entry_price=price, base_price=price, loss_ref_price=price, profit_ref_price=price, ref_time=timezone.now(), modifier=default_modifier, discord_webhook=discord_webhook) task.save() return BuyStock() if Decimal(price): limit_price = Decimal(price).quantize(Decimal('0.0001')) else: quantized_margin = Decimal(margin).quantize(Decimal('0.001')) quote = etrade.get_quote(symbol) limit_price = get_limit_price( OrderAction.BUY, get_bid(quote), Decimal(quantized_margin) or strategy.price_margin) if not quantity: quantity = strategy.get_quantity_for( buying_power=account.real_value, price_per_share=limit_price) order_params = { 'account_key': account_key, 'market_session': MarketSession.current().value, 'action': OrderAction.BUY.value, 'symbol': symbol, 'price_type': PriceType.LIMIT.value, 'quantity': quantity, 'limit_price': limit_price } preview_ids = etrade.preview_order( order_client_id=get_random_string(length=20), **order_params) etrade.place_order(order_client_id=get_random_string(length=20), preview_ids=preview_ids, **order_params) # TODO: HANDLE Code: 1527. Message: Opening orders for this security cannot be accepted online at this time. For assistance with placing this order, please contact Customer Service at 1-800-ETRADE-1 (1-800-387-2331). return BuyStock()