예제 #1
0
    def run(self):
        start_time = datetime.now()
        PrinterUtils.console_log(
            message=
            f"Started trading at {start_time} and will ended at {self.__run_stop_time}"
        )

        delta_minutes = start_time
        while not TradeBotUtils.is_run_time_passed(
                current_time=datetime.now(),
                run_stop_time=self.__run_stop_time):

            delta_minutes = self.__print_trading_data(delta_minutes)

            try:
                if self.__trade_bot.is_account_order_matching_market_order():
                    order_id = self.__trade_bot.execute_order()
                    if self.__trade_bot.is_order_executed(order_id):
                        self.__trade_bot.run_post_trade_tasks(order_id)
                        self.__switch_trader()
            except (websockets.exceptions.ConnectionClosedError,
                    websockets.exceptions.ConnectionClosedOK,
                    websockets.exceptions.InvalidStatusCode) as e:
                self.__reconnect_websocket()

        PrinterUtils.console_log(
            message=
            f"Started trading at {start_time} and ended at {datetime.now()}")
예제 #2
0
 def init_trades_to_database_from_exchange(
         self, database_service: DatabaseService):
     PrinterUtils.console_log(message=f"Initializing Database from kraken!")
     closed_transactions = self.get_transactions()
     trade_nr = 1
     for idx, order_id in enumerate(
             reversed(list(closed_transactions.keys()))):
         if self.__is_successful_order(closed_transactions, order_id):
             database_service.insert_trade_report(
                 order_id=order_id,
                 is_live=True,
                 exchange='kraken',
                 timestamp=self.get_transaction_timestamp(
                     closed_transactions[order_id]),
                 trade_number=trade_nr,
                 buy=self.is_transaction_buy(closed_transactions[order_id]),
                 cash_currency=self.get_transaction_cash_currency(
                     closed_transactions[order_id]),
                 crypto_currency=self.get_transaction_crypto_currency(
                     closed_transactions[order_id]),
                 fee=self.get_transaction_fee_from_transaction_dict(
                     closed_transactions[order_id]),
                 price=self.get_transaction_price_per_quantity(
                     closed_transactions[order_id]),
                 quantity=self.get_transaction_quantity(
                     closed_transactions[order_id]),
                 gross_trade_value=self.get_transaction_gross_value(
                     closed_transactions[order_id]),
                 net_trade_value=self.get_transaction_net_value(
                     closed_transactions[order_id]))
             trade_nr += 1
예제 #3
0
    def run_queries_from_file(self, file_path):
        with open(file_path, 'r') as sql_file:
            queries = sql_file.read().strip().split(';')
        for query in [f'{query};' for query in queries]:
            self.write_query(query=query, data=[])

        PrinterUtils.console_log(message=f'Query Executed: Run Queries from File')
 def __get_transactions(self) -> DataFrame:
     PrinterUtils.console_log("Fetching Transactions from Database")
     query = f"SELECT * FROM tax_management.trades"
     transactions = self._database_service.custom_read_query_to_dataframe(
         query=query).sort_values(by=['datetime']).reset_index(drop=True)
     self.__convert_currencies(transactions)
     return transactions
예제 #5
0
    def _get_initial_bid_price(self,
                               exchange_websocket: ExchangeWebsocket) -> float:
        if self._configs.is_sell:
            return 0

        is_invalid_account_bid_price = True
        account_bid_price = 0
        while is_invalid_account_bid_price:
            market_bid_price = exchange_websocket.get_market_bid_price()
            market_ask_price = exchange_websocket.get_market_ask_price()
            print(
                f'\nMarket bid: {market_bid_price} \nMarket ask: {market_ask_price}'
            )

            account_bid_price = float(input('Set start account BID price: '))
            is_invalid_account_bid_price = market_ask_price - account_bid_price < 0
            if is_invalid_account_bid_price:
                PrinterUtils.console_log(
                    message=
                    "ERROR: Account bid price has to be smaller than market ask price."
                )
            else:
                PrinterUtils.console_log(
                    message=f"Account Bid Price: {account_bid_price}")

        return account_bid_price
예제 #6
0
    def get_accrued_account_fees(self, exchange: str, cash_currency: str,
                                 crypto_currency: str, is_live: bool) -> float:
        accrued_fee = 0
        for currency in TradeBotUtils.get_permitted_cash_currencies():
            query = "SELECT SUM(fee) from trade_data.report" \
                    " WHERE live = %s" \
                    " AND exchange = %s" \
                    " AND cash_currency = %s" \
                    " AND crypto_currency = %s;"
            data = [
                is_live,
                exchange.lower(),
                currency.lower(),
                crypto_currency.lower()
            ]
            result = self.read_query(query=query, data=data)[0][0]
            if result:
                accrued_fee += self._currency_converter.convert_currency_from_api(
                    value=float(result),
                    from_currency=currency,
                    to_currency=cash_currency)

        PrinterUtils.console_log(
            message=f'Query Executed: Get Accrued Account Fees')
        return float(accrued_fee)
예제 #7
0
 def custom_read_query(self, query: str, data: list):
     result = self.read_query(query, data)[0][0]
     if isinstance(result, decimal.Decimal):
         return float(result)
     if isinstance(result, str):
         return str(result)
     PrinterUtils.console_log(message=f'Custom Query Executed')
     return result
예제 #8
0
 def __reconnect_websocket(self):
     wait_time_in_seconds = 120
     PrinterUtils.console_log(
         message=
         f"{datetime.now()}: Attempting to Reconnect Websocket in {wait_time_in_seconds} seconds"
     )
     time.sleep(wait_time_in_seconds)
     self.__trade_bot.reconnect_websocket()
예제 #9
0
 def __send_email(self, message: MIMEMultipart):
     server = smtplib.SMTP('smtp.gmail.com', 587)
     server.starttls()
     server.login(self.__email_source, self.__email_source_password)
     text = message.as_string()
     server.sendmail(self.__email_source, self.__email_target, text)
     server.quit()
     PrinterUtils.console_log(message=f'Email Sent: {datetime.now()}')
    def tax_calculations(self):
        all_transactions = self.__get_transactions()
        k4_values = []
        for crypto_currency in all_transactions.crypto_currency.unique():
            PrinterUtils.console_log(f"Calculating for {crypto_currency}! --")
            transactions = all_transactions[all_transactions["crypto_currency"]
                                            == crypto_currency].reset_index(
                                                drop=True)
            self.__save_transactions(transactions, crypto_currency)

            total_overhead_value = 0
            avg_overhead_value = 0
            total_quantity = -self.reserved_xrp(
            ) if crypto_currency == "xrp" else 0
            total_profit = 0
            overhead_value_calculations = []
            for idx in transactions.index.values:
                transaction = transactions.iloc[idx]

                if transaction['buy']:
                    total_quantity += transaction["quantity"]
                    total_overhead_value += transaction['gross_trade_value']
                    avg_overhead_value = total_overhead_value / total_quantity
                    profit = 0
                else:
                    total_quantity -= transaction["quantity"]
                    total_overhead_value -= avg_overhead_value * transaction[
                        'quantity']
                    profit = transaction['net_trade_value'] - transaction[
                        'quantity'] * avg_overhead_value
                    total_profit += profit

                    if transaction["quantity"] >= math.pow(10, -5):
                        k4_values.append([
                            transaction['datetime'], crypto_currency,
                            transaction["quantity"],
                            transaction['net_trade_value'],
                            transaction["quantity"] * avg_overhead_value
                        ])

                overhead_value_calculations.append([
                    transaction['datetime'],
                    "Köp" if transaction["buy"] else "Sälj", total_quantity,
                    total_overhead_value, avg_overhead_value,
                    "" if profit <= math.pow(10, -5) else profit,
                    "" if profit <= math.pow(10, -5) else profit *
                    self.__tax_percent, "", total_profit,
                    total_profit * self.__tax_percent
                ])

            self.__save_overhead_value_calulations(overhead_value_calculations,
                                                   crypto_currency)
            self.__print_current_values(total_quantity, total_overhead_value,
                                        avg_overhead_value, total_profit)

        if k4_values:
            self.__save_k4(k4_values)
예제 #11
0
 def __log_trading_data(self, is_buy: bool, headers: list, output: list):
     headers[1] = "Account Trade Price"
     headers[2] = "Market Trade Price"
     headers.insert(1, "Is Buy")
     output.insert(1, is_buy)
     PrinterUtils.log_data(
         headers=headers,
         output=output,
         file_path=TradeBotUtils.get_generated_file_path(
             f"{self.__exchange_name.lower()}_trading_data_log.csv"))
예제 #12
0
    def print_trading_data(self, is_buy: bool):
        if is_buy:
            account_trade = f"Account Bid Price [{self.__currency_symbols[self.__cash_currency]}]"
            account_trade_price = trading_cache.account_bid_price

            market_trade = f"Market Ask Price [{self.__currency_symbols[self.__cash_currency]}]"
            market_trade_price = trading_cache.market_ask_price

            current_value_description = "Cash Value"
            current_value = trading_cache.cash_value

            trade_quantity = f"Buy Quantity {self.__crypto_currency.upper()}"
            trade_quantity_value = trading_cache.buy_quantity

            percent_profit = "Cash Profit [%]"
            percent_profit_value = ProfitCalculatorUtil.percent_cash_profit(
                cash_value=current_value,
                initial_value=trading_cache.initial_value)

        else:
            account_trade = f"Account Ask Price [{self.__currency_symbols[self.__cash_currency]}]"
            account_trade_price = trading_cache.account_ask_price

            market_trade = f"Market Bid Price [{self.__currency_symbols[self.__cash_currency]}]"
            market_trade_price = trading_cache.market_bid_price

            current_value_description = f"Position Net Value [{self.__currency_symbols[self.__cash_currency]}]"
            current_value = trading_cache.net_position_value

            trade_quantity = f"Sell Quantity {self.__crypto_currency.upper()}"
            trade_quantity_value = trading_cache.sell_quantity

            percent_profit = "Position Profit [%]"
            percent_profit_value = ProfitCalculatorUtil.percent_cash_profit(
                cash_value=current_value,
                initial_value=trading_cache.initial_value)

        headers = [
            'Timestamp', trade_quantity, account_trade, market_trade,
            f'Initial Value [{self.__currency_symbols[self.__cash_currency]}]',
            current_value_description, percent_profit,
            f'Accrued Fees [{self.__currency_symbols[self.__cash_currency]}]',
            'Nr Buy+Sell Cycles'
        ]

        output = [
            datetime.now(), trade_quantity_value, account_trade_price,
            market_trade_price, trading_cache.initial_value, current_value,
            percent_profit_value, trading_cache.accrued_fee,
            trading_cache.successful_cycles
        ]

        PrinterUtils.print_data_as_tabulate(headers=headers, output=output)

        self.__log_trading_data(is_buy, headers, output)
예제 #13
0
    def get_initial_account_value(self, exchange: str, is_live: bool,
                                  cash_currency: str) -> float:
        query = f"SELECT initial_account_value_{cash_currency.lower()} from trade_data.initial_account_value" \
                f" WHERE exchange = %s" \
                f" AND live = %s;"
        data = [exchange, is_live]
        result = self.read_query(query=query, data=data)

        PrinterUtils.console_log(
            message=f'Query Executed: Get initial Account Value')
        return float(result[0][0]) if result else 0
예제 #14
0
    def drop_schema_tables(self, schema: str):
        query = "SELECT table_name FROM information_schema.tables" \
                " WHERE table_schema = %s"
        data = [schema]
        table_names = self.read_query(query, data)
        table_names = [f"{schema}." + table_name[0] for table_name in table_names]
        separator = ', '
        query = f"DROP TABLE {separator.join(table_names)}"
        self.write_query(query=query, data=[])

        PrinterUtils.console_log(message=f'Query Executed: Drop all Schema Tables')
예제 #15
0
 def _get_exchange_websocket(self) -> ExchangeWebsocket:
     PrinterUtils.console_log(
         message=
         f"Exchange {self._configs.exchange} WebSocket is being used for trading {self._configs.crypto_currency}"
         f" in {self._configs.cash_currency}")
     if self._configs.exchange == 'bitstamp':
         return BitstampWebsocket(self._configs.cash_currency,
                                  self._configs.crypto_currency)
     else:
         return KrakenWebsocket(self._configs.cash_currency,
                                self._configs.crypto_currency)
예제 #16
0
    def insert_trade_report(self, is_live: bool, exchange: str, trade_number: int, timestamp: datetime, order_id: str, buy: bool, price: float,
                            cash_currency: str, quantity: float, crypto_currency: str, fee: float, gross_trade_value: float, net_trade_value: float):
        query = f'INSERT INTO tax_management.trades(order_id, live, exchange,' \
                ' datetime, account_trade_number, buy, price, cash_currency,' \
                ' quantity, crypto_currency, fee, gross_trade_value, net_trade_value) ' \
                'VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) ON CONFLICT DO NOTHING;'
        data = [order_id, is_live, exchange.lower(), timestamp, trade_number, buy,
                price, cash_currency.lower(), quantity, crypto_currency.lower(), fee, gross_trade_value, net_trade_value]

        self.write_query(query=query, data=data)

        PrinterUtils.console_log(message=f'Query Executed: Insert Trade Report')
예제 #17
0
 def get_nr_successful_cycles(self, exchange: str, crypto_currency: str,
                              is_live: bool) -> int:
     query = "SELECT COUNT(account_trade_number) from trade_data.report" \
             " WHERE live = %s " \
             " AND buy = %s" \
             " AND exchange = %s" \
             " AND crypto_currency = %s;"
     data = [is_live, False, exchange.lower(), crypto_currency]
     result = self.read_query(query=query, data=data)[0][0]
     PrinterUtils.console_log(
         message=f'Query Executed: Get nr of Successful Cycles')
     return int(result) if result else 0
 def __print_current_values(self, total_quantity: float,
                            total_overhead_value: float,
                            avg_overhead_value: float, total_profit: float):
     headers = [
         "Date", "Total Quantity", "Total Overhead Value",
         "Average Overhead value", "Total Profit", "Total Tax"
     ]
     output = [
         date.today(), total_quantity, total_overhead_value,
         avg_overhead_value, total_profit, total_profit * self.__tax_percent
     ]
     PrinterUtils.console_log(message=f"Current State --")
     PrinterUtils.print_data_as_tabulate(headers=headers, output=output)
예제 #19
0
 def __live_run_checker(self):
     if self.__configs.is_live:
         contract_pin = random.randint(10000, 99999)
         signature = int(
             input(
                 f"\nWARNING LIVE RUN. If you want to trade sign the contract by entering: {contract_pin}: "
             ))
         if signature != int(contract_pin):
             PrinterUtils.console_log(message="ABORTING")
             exit()
         else:
             PrinterUtils.console_log(
                 message="Contract signed! Live run accepted!")
 def __save_tax_report_yearly_sales_per_crypto_currency(
         self, overhead_value_calculations_df: DataFrame,
         crypto_currency: str):
     calculated_sell_transactions_df = overhead_value_calculations_df.loc[
         overhead_value_calculations_df['Händelse'] == "Sälj"]
     overhead_value_calculations_df = calculated_sell_transactions_df.loc[
         calculated_sell_transactions_df['Datum'].dt.year == self._year]
     overhead_value_calculations_df.to_csv(
         TaxManagementUtils.get_generated_file_path(
             f"overhead_value_calculations_sales_{crypto_currency}_{self._year}.csv"
         ))
     PrinterUtils.console_log(
         message=f"Tax Report {self._year} Saved for {crypto_currency}")
 def __convert_currencies(self, transactions: DataFrame):
     PrinterUtils.console_log(message="Converting values to SEK")
     columns_to_convert = ['fee', "gross_trade_value", "net_trade_value"]
     conversion_fee = 0.02
     for column in columns_to_convert:
         transactions[column] = transactions.apply(
             lambda x: x[column]
             if x['cash_currency'] == 'sek' else (1 - conversion_fee) * self
             ._currency_converter.convert_currency_from_api(
                 value=x[column],
                 from_currency=x['cash_currency'],
                 to_currency='sek',
                 date=x['datetime'].strftime("%Y-%m-%d")),
             axis=1)
예제 #22
0
    def is_order_executed(self, order_id: str) -> bool:
        time.sleep(5)
        while self.__is_order_status_open(order_id):
            PrinterUtils.console_log(
                message=f"Order id {order_id} is still open")
            time.sleep(20)

        if self.__is_order_executed(order_id):
            return True
        else:
            PrinterUtils.console_log(
                message=
                f'{datetime.now()} - Order: {order_id} was not executed!')
            time.sleep(5)
            return False
예제 #23
0
    def print_and_store_trade_report(self, is_buy: bool, fee: float,
                                     order_id: str):
        if is_buy:
            value = trading_cache.cash_value
            quantity = trading_cache.buy_quantity
            price = trading_cache.market_ask_price
        else:
            value = trading_cache.gross_position_value
            quantity = trading_cache.sell_quantity
            price = trading_cache.market_bid_price

        headers = [
            'Timestamp', 'is_live', 'exchanges', 'Trade Number', 'Is Buy',
            f'Price [{self.__currency_symbols[self.__cash_currency]}]',
            f'Quantity {self.__crypto_currency.upper()}',
            f'Gross Trade Value [{self.__currency_symbols[self.__cash_currency]}]',
            f'Net Trade Value [{self.__currency_symbols[self.__cash_currency]}]',
            f'Fee [{self.__currency_symbols[self.__cash_currency]}]'
        ]
        output = [
            datetime.now(), self.__is_live, self.__exchange_name,
            trading_cache.successful_trades, is_buy, price, quantity, value,
            value - fee, fee
        ]

        PrinterUtils.print_data_as_tabulate(headers, output)
        PrinterUtils.log_data(
            headers=headers,
            output=output,
            file_path=TradeBotUtils.get_generated_file_path(
                f"{self.__exchange_name.lower()}_successful_trade_log.csv"))

        self.__database_service.insert_trade_report(
            order_id=order_id,
            is_live=self.__is_live,
            exchange=self.__exchange_name,
            trade_number=trading_cache.successful_trades,
            timestamp=datetime.now(),
            buy=is_buy,
            price=price,
            quantity=quantity,
            cash_currency=self.__cash_currency,
            crypto_currency=self.__crypto_currency,
            gross_trade_value=value,
            net_trade_value=value - fee,
            fee=fee)
예제 #24
0
 def get_transactions_as_dataframe(self, exchange: str, is_live: bool,
                                   cash_currency: str,
                                   crypto_currency: str) -> DataFrame:
     query = "SELECT buy, cash_currency, net_trade_value, account_trade_number from trade_data.report" \
             " WHERE live = {}" \
             " AND exchange = '{}'" \
             " AND crypto_currency = '{}';" \
         .format(is_live, exchange.lower(), crypto_currency.lower())
     transaction_df = self.read_to_dataframe(query)
     transaction_df['net_trade_value'] = transaction_df.apply(
         lambda x: x['net_trade_value'] if x[
             'cash_currency'] == cash_currency else self._currency_converter
         .convert_currency_from_api(value=x['net_trade_value'],
                                    from_currency=x['cash_currency'],
                                    to_currency=cash_currency),
         axis=1)
     PrinterUtils.console_log(
         message=f'Query Executed: Get Transaction as DataFrame')
     return transaction_df
    def __get_exchange_api(self) -> ExchangeApi:
        PrinterUtils.console_log(message=f"Exchange {self._configs.exchange} Api is being used for trading {self._configs.crypto_currency}"
                                         f" in {self._configs.cash_currency} with interest: {self._configs.interest * 100}%")

        if self._configs.exchange == 'bitstamp':
            exchange_api = BitstampApi(cash_currency=self._configs.cash_currency,
                                       crypto_currency=self._configs.crypto_currency,
                                       customer_id=TradeBotUtils.get_bitstamp_customer_id(),
                                       api_key=TradeBotUtils.get_bitstamp_api_key(),
                                       api_secret=TradeBotUtils.get_bitstamp_api_secret())
        else:
            exchange_api = KrakenApi(cash_currency=self._configs.cash_currency,
                                     crypto_currency=self._configs.crypto_currency,
                                     api_key=TradeBotUtils.get_kraken_api_key(),
                                     api_secret=TradeBotUtils.get_kraken_api_secret())

        if self._configs.init_database_from_exchange:
            exchange_api.init_trades_to_database_from_exchange(database_service=self._database_service)

        return exchange_api
예제 #26
0
    def insert_or_update_initial_account_value(self, exchange: str,
                                               is_live: bool,
                                               account_value: float,
                                               cash_currency: str):
        query = "INSERT INTO trade_data.initial_account_value(exchange, live, initial_account_value_usd, initial_account_value_eur)" \
                " VALUES(%s, %s, %s, %s)" \
                " ON CONFLICT (exchange, live) " \
                " DO UPDATE" \
                " SET" \
                " initial_account_value_usd = excluded.initial_account_value_usd," \
                " initial_account_value_eur = excluded.initial_account_value_eur;"
        data = [
            exchange, is_live,
            self._currency_converter.convert_currency_from_api(
                account_value, cash_currency, 'usd'),
            self._currency_converter.convert_currency_from_api(
                account_value, cash_currency, 'eur')
        ]
        self.write_query(query=query, data=data)

        PrinterUtils.console_log(
            message=f'Query Executed: Insert initial Account Value')
예제 #27
0
 async def __async__connect(self):
     PrinterUtils.console_log(message="Attempting connection to {}".format(self.__uri))
     self._websocket = await websockets.connect(self.__uri)
     PrinterUtils.console_log(message="Connected")
예제 #28
0
 def run_post_trade_tasks(self, order_id: str):
     fee = trading_cache.cash_value * trading_cache.exchange_fee
     self.update_cache(order_id, fee)
     self._create_visual_trade_report()
     self._email_trade_reports()
     PrinterUtils.console_log(message="Post Trade Task Finished!")
예제 #29
0
 def run_post_trade_tasks(self, order_id: str):
     fee = self.__exchange_api.get_transaction_fee(order_id)
     self.update_cache(order_id, fee)
     self._create_visual_trade_report()
     self._email_trade_reports()
     PrinterUtils.console_log(message="Post Trade Task Finished!")