internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: rotki/rotki

Issue:
fixer.io currency exchange API has moved to subscription based queries -- breaks the app
http://api.fixer.io/ is down and has switched to a subscription based API.

![2018-06-05-115728_943x260_scrot](https://user-images.githubusercontent.com/1658405/40969237-a984b3a0-68b7-11e8-8c91-8b4e01873074.png)

![2018-06-05-115714_1183x809_scrot](https://user-images.githubusercontent.com/1658405/40969256-ba88ab3e-68b7-11e8-97cb-2660db68aa4b.png)

Switch to another free API service for now. In the future need to have a more reliable way of querying data that will try alternative services if one service fails.


Discussion:

Resolving patch:
diff --git a/rotkehlchen/utils.py b/rotkehlchen/utils.py
--- a/rotkehlchen/utils.py
+++ b/rotkehlchen/utils.py
@@ -95,20 +95,15 @@ def wrapper(wrappingobj, *args):
     return _cache_response_timewise
 
 
-def query_fiat_pair(base, quote, timestamp=None):
+def query_fiat_pair(base, quote):
     if base == quote:
         return FVal(1.0)
 
-    if timestamp is None:
-        querystr = 'http://api.fixer.io/latest?base={}'.format(base)
-    else:
-        querystr = 'http://api.fixer.io/{}?base={}'.format(
-            tsToDate(timestamp, formatstr='%Y-%m-%d'), base
-        )
-
+    pair = '{}_{}'.format(base, quote)
+    querystr = 'https://free.currencyconverterapi.com/api/v5/convert?q={}'.format(pair)
     resp = request_get(querystr)
     try:
-        return FVal(resp['rates'][quote])
+        return FVal(resp['results'][pair]['val'])
     except ValueError:
         raise ValueError('Could not find a "{}" price for "{}"'.format(base, quote))
 


Test patch:
Repository: rotki/rotki

Issue:
Retrieving tax_free_after_period from DB throws error
Retrieving tax_free_after_period from DB throws error since it's not properly turned to int from a string.


Discussion:

Resolving patch:
diff --git a/rotkehlchen/accounting/events.py b/rotkehlchen/accounting/events.py
--- a/rotkehlchen/accounting/events.py
+++ b/rotkehlchen/accounting/events.py
@@ -53,6 +53,8 @@ def taxfree_after_period(self):
 
     @taxfree_after_period.setter
     def taxfree_after_period(self, value):
+        is_valid = isinstance(value, int) or value is None
+        assert is_valid, 'set taxfree_after_period should only get int or None'
         self._taxfree_after_period = value
 
     def calculate_asset_details(self):
diff --git a/rotkehlchen/db/dbhandler.py b/rotkehlchen/db/dbhandler.py
--- a/rotkehlchen/db/dbhandler.py
+++ b/rotkehlchen/db/dbhandler.py
@@ -204,6 +204,8 @@ def get_settings(self):
                 settings['last_data_upload_ts'] = int(q[1])
             elif q[0] == 'ui_floating_precision':
                 settings['ui_floating_precision'] = int(q[1])
+            elif q[0] == 'taxfree_after_period':
+                settings['taxfree_after_period'] = int(q[1])
             else:
                 settings[q[0]] = q[1]
 


Test patch:
diff --git a/rotkehlchen/tests/test_db.py b/rotkehlchen/tests/test_db.py
--- a/rotkehlchen/tests/test_db.py
+++ b/rotkehlchen/tests/test_db.py
@@ -260,3 +260,30 @@ def test_upgrade_db_1_to_2(data_dir, username):
     accounts = data.db.get_blockchain_accounts()
     assert accounts['ETH'][0] == '0xe3580C38B0106899F45845E361EA7F8a0062Ef12'
     assert data.db.get_version() == ROTKEHLCHEN_DB_VERSION
+
+
+def test_settings_entry_types(data_dir, username):
+    data = DataHandler(data_dir)
+    data.unlock(username, '123', create_new=True)
+
+    data.db.set_settings({
+        'version': 1,
+        'last_write_ts': 1,
+        'premium_should_sync': True,
+        'include_crypto2crypto': True,
+        'last_data_upload_ts': 1,
+        'ui_floating_precision': 1,
+        'taxfree_after_period': 1,
+        'historical_data_start': '01/08/2015',
+        'eth_rpc_port': '8545',
+    })
+
+    res = data.db.get_settings()
+    assert isinstance(res['db_version'], int)
+    assert isinstance(res['last_write_ts'], int)
+    assert isinstance(res['premium_should_sync'], bool)
+    assert isinstance(res['include_crypto2crypto'], bool)
+    assert isinstance(res['ui_floating_precision'], int)
+    assert isinstance(res['taxfree_after_period'], int)
+    assert isinstance(res['historical_data_start'], str)
+    assert isinstance(res['eth_rpc_port'], str)
Repository: rotki/rotki

Issue:
AttributeError during addition of new token
When trying to add a new token via the UI I get the following:

` AttributeError: 'Rotkehlchen' object has no attribute 'rotkehlchen'`


Discussion:

Resolving patch:
diff --git a/rotkehlchen/rotkehlchen.py b/rotkehlchen/rotkehlchen.py
--- a/rotkehlchen/rotkehlchen.py
+++ b/rotkehlchen/rotkehlchen.py
@@ -358,7 +358,7 @@ def add_owned_eth_tokens(self, tokens):
         except InputError as e:
             return simple_result(False, str(e))
 
-        self.data.write_owned_eth_tokens(self.rotkehlchen.blockchain.owned_eth_tokens)
+        self.data.write_owned_eth_tokens(self.blockchain.owned_eth_tokens)
         return accounts_result(new_data['per_account'], new_data['totals'])
 
     def remove_owned_eth_tokens(self, tokens):
@@ -366,7 +366,7 @@ def remove_owned_eth_tokens(self, tokens):
             new_data = self.blockchain.remove_eth_tokens(tokens)
         except InputError as e:
             return simple_result(False, str(e))
-        self.data.write_owned_eth_tokens(self.rotkehlchen.blockchain.owned_eth_tokens)
+        self.data.write_owned_eth_tokens(self.blockchain.owned_eth_tokens)
         return accounts_result(new_data['per_account'], new_data['totals'])
 
     def process_history(self, start_ts, end_ts):


Test patch:
diff --git a/rotkehlchen/tests/test_api.py b/rotkehlchen/tests/test_api.py
--- a/rotkehlchen/tests/test_api.py
+++ b/rotkehlchen/tests/test_api.py
@@ -1,6 +1,29 @@
+import pytest
 
 
 def test_add_remove_blockchain_account(rotkehlchen_instance):
     """Test for issue 66 https://github.com/rotkehlchenio/rotkehlchen/issues/66"""
-    rotkehlchen_instance.add_blockchain_account('ETH', '0x00d74c25bbf93df8b2a41d82b0076843b4db0349')
-    rotkehlchen_instance.remove_blockchain_account('ETH', '0x00d74C25bBf93Df8B2A41d82B0076843B4dB0349')
+    rotkehlchen_instance.add_blockchain_account(
+        'ETH',
+        '0x00d74c25bbf93df8b2a41d82b0076843b4db0349'
+    )
+    rotkehlchen_instance.remove_blockchain_account(
+        'ETH',
+        '0x00d74C25bBf93Df8B2A41d82B0076843B4dB0349'
+    )
+
+
+@pytest.mark.parametrize('number_of_accounts', [0])
+def test_add_remove_eth_tokens(rotkehlchen_instance):
+    """Test for issue 83 https://github.com/rotkehlchenio/rotkehlchen/issues/83"""
+    # Addition of tokens into the DB fires up balance checks for each account
+    # we got. For that reason we give 0 accounts for this test
+
+    tokens_to_add = ['STORJ', 'GNO', 'RDN']
+    rotkehlchen_instance.add_owned_eth_tokens(tokens_to_add)
+    db_tokens_list = rotkehlchen_instance.data.db.get_owned_tokens()
+    assert set(tokens_to_add) == set(db_tokens_list)
+
+    rotkehlchen_instance.remove_owned_eth_tokens(['STORJ', 'GNO'])
+    db_tokens_list = rotkehlchen_instance.data.db.get_owned_tokens()
+    assert len(db_tokens_list) == 1 and db_tokens_list[0] == 'RDN'
Repository: rotki/rotki

Issue:
Providing invalid API key for kraken or binance does not throw appropriate error
Providing an invalid API key for kraken or binance will fail, but with an unknown error. That's due to a bug in the way the validaton of the key happens for these 2 exchanges. Easy to fix.


Discussion:

Resolving patch:
diff --git a/rotkehlchen/binance.py b/rotkehlchen/binance.py
--- a/rotkehlchen/binance.py
+++ b/rotkehlchen/binance.py
@@ -99,9 +99,9 @@ def validate_api_key(self) -> Tuple[bool, str]:
             error = str(e)
             if 'API-key format invalid' in error:
                 return False, 'Provided API Key is in invalid Format'
-            elif 'Signature for this request is not valid':
+            elif 'Signature for this request is not valid' in error:
                 return False, 'Provided API Secret is malformed'
-            elif 'Invalid API-key, IP, or permissions for action':
+            elif 'Invalid API-key, IP, or permissions for action' in error:
                 return False, 'API Key does not match the given secret'
             else:
                 raise
diff --git a/rotkehlchen/kraken.py b/rotkehlchen/kraken.py
--- a/rotkehlchen/kraken.py
+++ b/rotkehlchen/kraken.py
@@ -144,7 +144,7 @@ def validate_api_key(self) -> Tuple[bool, str]:
             error = str(e)
             if 'Error: Incorrect padding' in error:
                 return False, 'Provided API Key or secret is in invalid Format'
-            elif 'EAPI:Invalid key':
+            elif 'EAPI:Invalid key' in error:
                 return False, 'Provided API Key is invalid'
             else:
                 raise


Test patch:
Repository: rotki/rotki

Issue:
Kraken: Deposit/withdrawals endpoint response causes warnings
The deposits and withdrawals endpoint for the Kraken exchange are misbehaving and making rotkehlchen think there is more deposits/withdrawals than there is. For more info look at #116 


Discussion:

Resolving patch:
diff --git a/rotkehlchen/kraken.py b/rotkehlchen/kraken.py
--- a/rotkehlchen/kraken.py
+++ b/rotkehlchen/kraken.py
@@ -338,6 +338,10 @@ def query_until_finished(
         """
         result: List = list()
 
+        logger.debug(
+            f'Querying Kraken {endpoint} from {start_ts} to '
+            f'{end_ts} with extra_dict {extra_dict}',
+        )
         response = self._query_endpoint_for_period(
             endpoint=endpoint,
             start_ts=start_ts,
@@ -348,7 +352,13 @@ def query_until_finished(
         offset = len(response[keyname])
         result.extend(response[keyname].values())
 
+        logger.debug(f'Kraken {endpoint} Query Response with count:{count}')
+
         while offset < count:
+            logger.debug(
+                f'Querying Kraken {endpoint} from {start_ts} to {end_ts} '
+                f'with offset {offset} and extra_dict {extra_dict}',
+            )
             response = self._query_endpoint_for_period(
                 endpoint=endpoint,
                 start_ts=start_ts,
@@ -360,6 +370,11 @@ def query_until_finished(
             response_length = len(response[keyname])
             offset += response_length
             if response_length == 0 and offset != count:
+                # If we have provided specific filtering then this is a known
+                # issue documented below, so skip the warning logging
+                # https://github.com/rotkehlchenio/rotkehlchen/issues/116
+                if extra_dict:
+                    break
                 # it is possible that kraken misbehaves and either does not
                 # send us enough results or thinks it has more than it really does
                 logger.warning(
@@ -430,14 +445,14 @@ def query_deposits_withdrawals(
                 keyname='ledger',
                 start_ts=start_ts,
                 end_ts=end_ts,
-                extra_dict=dict(type='deposit')
+                extra_dict=dict(type='deposit'),
             )
             result.extend(self.query_until_finished(
                 endpoint='Ledgers',
                 keyname='ledger',
                 start_ts=start_ts,
                 end_ts=end_ts,
-                extra_dict=dict(type='withdrawal')
+                extra_dict=dict(type='withdrawal'),
             ))
 
             with self.lock:
@@ -459,4 +474,5 @@ def query_deposits_withdrawals(
                 amount=FVal(movement['amount']),
                 fee=FVal(movement['fee'])
             ))
+
         return movements


Test patch:
Repository: rotki/rotki

Issue:
Do not log an error for not finding the manual margins file
This file is only used by poloniex and since margin trades can't be easily audited in that platform. As such logging an error if one is not found is not correct.


Discussion:

Resolving patch:
diff --git a/rotkehlchen/history.py b/rotkehlchen/history.py
--- a/rotkehlchen/history.py
+++ b/rotkehlchen/history.py
@@ -133,7 +133,7 @@ def do_read_manual_margin_positions(data_directory):
             margin_data = rlk_jsonloads(f.read())
     else:
         margin_data = []
-        logger.error(
+        logger.info(
             'Could not find manual margins log file at {}'.format(manual_margin_path)
         )
     return margin_data


Test patch:
Repository: rotki/rotki

Issue:
BTG or other assets with no market in bittrex crash the app
## Problem Definition

If a user holds an asset in bittrex that does not have a market in the exchange, like say `BTG`, then during balances query rotkehlchen will crash with `ValueError: Bittrex: Could not find BTC market for "BTG"`

## Task

Fix the crash, and use other sources for market price data in the case this happens.


Discussion:

Resolving patch:
diff --git a/rotkehlchen/bittrex.py b/rotkehlchen/bittrex.py
--- a/rotkehlchen/bittrex.py
+++ b/rotkehlchen/bittrex.py
@@ -1,24 +1,24 @@
-import time
-import hmac
 import hashlib
-from urllib.parse import urlencode
+import hmac
+import logging
+import time
 from json.decoder import JSONDecodeError
+from typing import Dict, List, Optional, Tuple, Union, cast
+from urllib.parse import urlencode
 
-from typing import Dict, Tuple, Optional, Union, List, cast
+from rotkehlchen import typing
+from rotkehlchen.errors import RemoteError
+from rotkehlchen.exchange import Exchange
+from rotkehlchen.fval import FVal
+from rotkehlchen.inquirer import Inquirer
+from rotkehlchen.order_formatting import Trade
 from rotkehlchen.utils import (
+    cache_response_timewise,
     createTimeStamp,
     get_pair_position,
     rlk_jsonloads,
-    cache_response_timewise,
 )
-from rotkehlchen.exchange import Exchange
-from rotkehlchen.order_formatting import Trade
-from rotkehlchen.fval import FVal
-from rotkehlchen.errors import RemoteError
-from rotkehlchen.inquirer import Inquirer
-from rotkehlchen import typing
 
-import logging
 logger = logging.getLogger(__name__)
 
 BITTREX_MARKET_METHODS = {
@@ -160,9 +160,6 @@ def get_btc_price(self, asset: typing.BlockchainAsset) -> Optional[FVal]:
                 btc_price = FVal(market['Last'])
                 break
 
-        if btc_price is None:
-            raise ValueError('Bittrex: Could not find BTC market for "{}"'.format(asset))
-
         return btc_price
 
     @cache_response_timewise()
@@ -181,9 +178,10 @@ def query_balances(self) -> Tuple[Optional[dict], str]:
         returned_balances = dict()
         for entry in resp:
             currency = entry['Currency']
+            asset_btc_price = self.get_btc_price(currency)
             usd_price = self.inquirer.find_usd_price(
                 asset=currency,
-                asset_btc_price=self.get_btc_price(currency)
+                asset_btc_price=asset_btc_price
             )
 
             balance = dict()


Test patch:
Repository: rotki/rotki

Issue:
USD Value for IOTA is incorrect
## Problem Definition

The usd value reported on my exchange is inconsistent with the usd value that rotkehlchen shows.

I tried to find where the USD value is calculated for exchange assets and I found the following API call: [rotkehlchen.inquirer#L68](https://github.com/kascheri12/rotkehlchen/blob/master/rotkehlchen/inquirer.py#L68) 

The asset "IOTA" uses symbol "IOT" at the api endpoint therefore the incorrect rate is returned when querying: 
https://min-api.cryptocompare.com/data/price?fsym=IOTA&tsyms=USD
vs.
https://min-api.cryptocompare.com/data/price?fsym=IOT&tsyms=USD
USD Value for IOTA is incorrect
## Problem Definition

The usd value reported on my exchange is inconsistent with the usd value that rotkehlchen shows.

I tried to find where the USD value is calculated for exchange assets and I found the following API call: [rotkehlchen.inquirer#L68](https://github.com/kascheri12/rotkehlchen/blob/master/rotkehlchen/inquirer.py#L68) 

The asset "IOTA" uses symbol "IOT" at the api endpoint therefore the incorrect rate is returned when querying: 
https://min-api.cryptocompare.com/data/price?fsym=IOTA&tsyms=USD
vs.
https://min-api.cryptocompare.com/data/price?fsym=IOT&tsyms=USD


Discussion:

Resolving patch:
diff --git a/rotkehlchen/constants.py b/rotkehlchen/constants.py
--- a/rotkehlchen/constants.py
+++ b/rotkehlchen/constants.py
@@ -15,6 +15,7 @@
 S_BTC = cast(typing.NonEthTokenBlockchainAsset, 'BTC')
 S_ETH = cast(typing.NonEthTokenBlockchainAsset, 'ETH')
 S_DATACOIN = cast(typing.NonEthTokenBlockchainAsset, 'DATAcoin')
+S_IOTA = cast(typing.NonEthTokenBlockchainAsset, 'IOTA')
 
 S_RDN = cast(typing.EthToken, 'RDN')
 
diff --git a/rotkehlchen/inquirer.py b/rotkehlchen/inquirer.py
--- a/rotkehlchen/inquirer.py
+++ b/rotkehlchen/inquirer.py
@@ -6,7 +6,7 @@
 import requests
 
 from rotkehlchen import typing
-from rotkehlchen.constants import FIAT_CURRENCIES, S_DATACOIN, S_RDN, S_USD
+from rotkehlchen.constants import FIAT_CURRENCIES, S_DATACOIN, S_RDN, S_USD, S_IOTA
 from rotkehlchen.errors import RemoteError
 from rotkehlchen.fval import FVal
 from rotkehlchen.utils import query_fiat_pair, retry_calls, rlk_jsonloads
@@ -33,6 +33,8 @@ def world_to_cryptocompare(asset):
         asset = cast(typing.EthToken, 'RDN*')
     elif asset == S_DATACOIN:
         asset = cast(typing.NonEthTokenBlockchainAsset, 'DATA')
+    elif asset == S_IOTA:
+        asset = cast(typing.NonEthTokenBlockchainAsset, 'IOT')
 
     return asset
 


Test patch:
Repository: rotki/rotki

Issue:
If there is 0 balance across all entries, querying for total balance fails.
## Problem Definition

In the event that there is a balance of `0` across all entries (exchanges, fiat balances, blockchain e.t.c.) then the backend greenlet that queries for the overall balances crashes and never returns a response to the frontend.

Log entries:
```
06/10/2018 12:59:56 CEST -- INFO:rotkehlchen.rotkehlchen:query_balances called requested_save_data=False
06/10/2018 12:59:56 CEST -- INFO:rotkehlchen.rotkehlchen:query_fiat_balances called
06/10/2018 12:59:56 CEST -- ERROR:rotkehlchen.server:Greenlet for task 2 dies with exception: [<class 'decimal.DivisionUndefined'>].
Exception Name: <class 'decimal.InvalidOperation'>
Exception Info: [<class 'decimal.DivisionUndefined'>]
Traceback:
   File "src/gevent/greenlet.py", line 716, in gevent._greenlet.Greenlet.run
  File "/home/lefteris/w/rotkehlchen/rotkehlchen/server.py", line 101, in _query_async
    result = getattr(self, command)(**kwargs)
  File "/home/lefteris/w/rotkehlchen/rotkehlchen/server.py", line 229, in query_balances
    result = self.rotkehlchen.query_balances(save_data)
  File "/home/lefteris/w/rotkehlchen/rotkehlchen/rotkehlchen.py", line 518, in query_balances
    'percentage_of_net_value': (total / net_usd).to_percentage(),
  File "/home/lefteris/w/rotkehlchen/rotkehlchen/fval.py", line 105, in __rtruediv__
    return FVal(self.num.__rtruediv__(other))
```

It's essentially a division by zero.

## Task

Take into account the posibility of 0 balance and act accordingly in the backend to avoid division by zero.


Discussion:

Resolving patch:
diff --git a/rotkehlchen/rotkehlchen.py b/rotkehlchen/rotkehlchen.py
--- a/rotkehlchen/rotkehlchen.py
+++ b/rotkehlchen/rotkehlchen.py
@@ -473,13 +473,21 @@ def query_balances(self, requested_save_data=False):
         for entry in total_usd_per_location:
             name = entry[0]
             total = entry[1]
+            if net_usd != FVal(0):
+                percentage = (total / net_usd).to_percentage()
+            else:
+                percentage = '0%'
             stats['location'][name] = {
                 'usd_value': total,
-                'percentage_of_net_value': (total / net_usd).to_percentage(),
+                'percentage_of_net_value': percentage,
             }
 
         for k, v in combined.items():
-            combined[k]['percentage_of_net_value'] = (v['usd_value'] / net_usd).to_percentage()
+            if net_usd != FVal(0):
+                percentage = (v['usd_value'] / net_usd).to_percentage()
+            else:
+                percentage = '0%'
+            combined[k]['percentage_of_net_value'] = percentage
 
         result_dict = merge_dicts(combined, stats)
 


Test patch:
Repository: rotki/rotki

Issue:
Replace the log watcher functionality in the frontend
## Description

At the moment in the frontend we use a [log watching](https://github.com/rotkehlchenio/rotkehlchen/blob/ecd231b8d8c55f30a7f7ef54280fa19e7a15f5ba/ui/utils.js#L119) functionality in order to watch the log for warnings and errors and display them to the user.

The problem with this approach is that for big log files it seems the frontend is slowing down.

## Task

1. Think if this is really needed.
2a. If not remove it and remove the `Tail` node dependency.
2b. If yes perhaps find another way to achieve the same thing that does not have negative side-effects.


Discussion:

Resolving patch:
diff --git a/rotkehlchen/server.py b/rotkehlchen/server.py
--- a/rotkehlchen/server.py
+++ b/rotkehlchen/server.py
@@ -243,9 +243,12 @@ def query_balances_async(self, save_data=False):
         res = self.query_async('query_balances')
         return {'task_id': res}
 
-    def query_last_balance_save_time(self):
-        res = self.rotkehlchen.data.db.get_last_balance_save_time()
-        return res
+    def query_periodic_data(self):
+        """Will query for some client data that can change frequently"""
+        result = {}
+        result['last_balance_save'] = self.rotkehlchen.data.db.get_last_balance_save_time()
+        result['eth_node_connection'] = self.rotkehlchen.blockchain.ethchain.connected
+        return process_result(result)
 
     def get_eth_tokens(self):
         result = {


Test patch:
Repository: rotki/rotki

Issue:
Kraken balances query will fail due to BCH/BSV fork
## Problem Definition

BCH forked into BCHSV and Kraken started also supporting BCHSV. Rotkehlchen does not currently handle this correctly

## Task

Handle BCHSV for Kraken


Discussion:

Resolving patch:
diff --git a/rotkehlchen/kraken.py b/rotkehlchen/kraken.py
--- a/rotkehlchen/kraken.py
+++ b/rotkehlchen/kraken.py
@@ -63,6 +63,7 @@
     'XXVN': 'XVN',
     'XXDG': 'XDG',
     'XTZ': 'XTZ',
+    'BSV': 'BCHSV',
 }
 
 WORLD_TO_KRAKEN = {
@@ -96,6 +97,7 @@
     'XVN': 'XXVN',
     'XDG': 'XXDG',
     'XTZ': 'XTZ',
+    'BCHSV': 'BSV',
 }
 
 KRAKEN_ASSETS = (
@@ -118,6 +120,7 @@
     'XICN',
     'GNO',
     'BCH',
+    'BSV',
     'XXLM',
     'DASH',
     'EOS',


Test patch:
Repository: rotki/rotki

Issue:
OTC trades table no longer appears in the UI
## Problem Definition

The table in OTC trades no longer appears in the OTC trades pane of the UI

## Task

Fix it


Discussion:

Resolving patch:
diff --git a/rotkehlchen/server.py b/rotkehlchen/server.py
--- a/rotkehlchen/server.py
+++ b/rotkehlchen/server.py
@@ -160,7 +160,8 @@ def setup_exchange(self, name, api_key, api_secret):
 
     def query_otctrades(self):
         trades = self.rotkehlchen.data.get_external_trades()
-        return process_result(trades)
+        result = {'result': trades, 'message': ''}
+        return process_result(result)
 
     def add_otctrade(self, data):
         result, message = self.rotkehlchen.data.add_external_trade(data)


Test patch: