Repository: freqtrade/freqtrade
Pull request: Improve some api results
## Summary
API should return timestamps for dates so an application can decide on formatting itself.

## Quick changelog

- Fix inconsistency between /status and /trades (percent vs. ratio)
- add *timestamp key to trade output
- Return *timestamp values for /profit (closes #3364)


Problem statement:
REST RPC Formatting
{"version":"develop-d31a091d"}

### Observed Results: 

  * What happened?
JSON-RPC command 'profit' 
`"first_trade_date":"5 days ago","latest_trade_date":"a day ago"`

Difficult to parse for any real client (not telegram) in any programming langage and not precise.

  * What did you expect to happen?
the real datetime or a unix timestamp
(like the resturn of 'trades' cmd wich include both formated datetime and human readable)

Hints from issue discussion:
When you say "RPC" command - which RPC method are we talking about? 
telegram? rest? webhooks?

Also - please fill out the issue template containing which version you're using.
Now it makes more sense. #3369 should address this.

If i may ask - what are you building with it? 
We're working on a WebUI as well - if that's what you're trying to build: https://github.com/freqtrade/frequi

Combined efforts will lead to better results (due to increased Resources!)
Ok for #3369 
Making a simple android java client, as webhook (ifttt) and telegram doesnt fit my need.

Commit message: Address feedback

Patch to review:
diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py
index 3f7f4e0e9ee..da7137cba1e 100644
--- a/freqtrade/persistence.py
+++ b/freqtrade/persistence.py
@@ -257,10 +257,12 @@ def to_json(self) -> Dict[str, Any]:
             'fee_close_currency': self.fee_close_currency,
             'open_date_hum': arrow.get(self.open_date).humanize(),
             'open_date': self.open_date.strftime("%Y-%m-%d %H:%M:%S"),
+            'open_timestamp': int(self.open_date.timestamp() * 1000),
             'close_date_hum': (arrow.get(self.close_date).humanize()
                                if self.close_date else None),
             'close_date': (self.close_date.strftime("%Y-%m-%d %H:%M:%S")
                            if self.close_date else None),
+            'close_timestamp': int(self.close_date.timestamp() * 1000) if self.close_date else None,
             'open_rate': self.open_rate,
             'open_rate_requested': self.open_rate_requested,
             'open_trade_price': self.open_trade_price,
diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py
index 21f54de507d..cf222a238bb 100644
--- a/freqtrade/rpc/rpc.py
+++ b/freqtrade/rpc/rpc.py
@@ -135,9 +135,11 @@ def _rpc_trade_status(self) -> List[Dict[str, Any]]:
                 trade_dict = trade.to_json()
                 trade_dict.update(dict(
                     base_currency=self._freqtrade.config['stake_currency'],
-                    close_profit=fmt_close_profit,
+                    close_profit=trade.close_profit or None,
+                    close_profit_perc=fmt_close_profit,
                     current_rate=current_rate,
-                    current_profit=round(current_profit * 100, 2),
+                    current_profit=current_profit,
+                    current_profit_perc=round(current_profit * 100, 2),
                     open_order='({} {} rem={:.8f})'.format(
                         order['type'], order['side'], order['remaining']
                     ) if order else None,
@@ -312,7 +314,9 @@ def _rpc_trade_statistics(
             'profit_all_fiat': profit_all_fiat,
             'trade_count': len(trades),
             'first_trade_date': arrow.get(trades[0].open_date).humanize(),
+            'first_trade_timestamp': int(trades[0].open_date.timestamp() * 1000),
             'latest_trade_date': arrow.get(trades[-1].open_date).humanize(),
+            'latest_trade_timestamp': int(trades[-1].open_date.timestamp() * 1000),
             'avg_duration': str(timedelta(seconds=sum(durations) / num)).split('.')[0],
             'best_pair': bp_pair,
             'best_rate': round(bp_rate * 100, 2),
diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py
index dfda15a26d2..37c1077a71d 100644
--- a/freqtrade/rpc/telegram.py
+++ b/freqtrade/rpc/telegram.py
@@ -215,8 +215,8 @@ def _status(self, update: Update, context: CallbackContext) -> None:
                     "*Open Rate:* `{open_rate:.8f}`",
                     "*Close Rate:* `{close_rate}`" if r['close_rate'] else "",
                     "*Current Rate:* `{current_rate:.8f}`",
-                    "*Close Profit:* `{close_profit}`" if r['close_profit'] else "",
-                    "*Current Profit:* `{current_profit:.2f}%`",
+                    "*Close Profit:* `{close_profit_perc}`" if r['close_profit_perc'] else "",
+                    "*Current Profit:* `{current_profit_perc:.2f}%`",
 
                     # Adding initial stoploss only if it is different from stoploss
                     "*Initial Stoploss:* `{initial_stop_loss:.8f}` " +
diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py
index 63691dfb470..5d278895b15 100644
--- a/tests/rpc/test_rpc.py
+++ b/tests/rpc/test_rpc.py
@@ -49,6 +49,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
         'base_currency': 'BTC',
         'open_date': ANY,
         'open_date_hum': ANY,
+        'open_timestamp': ANY,
         'is_open': ANY,
         'fee_open': ANY,
         'fee_open_cost': ANY,
@@ -68,13 +69,16 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
         'open_order_id': ANY,
         'close_date': None,
         'close_date_hum': None,
+        'close_timestamp': None,
         'open_rate': 1.098e-05,
         'close_rate': None,
         'current_rate': 1.099e-05,
         'amount': 91.07468124,
         'stake_amount': 0.001,
         'close_profit': None,
-        'current_profit': -0.41,
+        'close_profit_perc': None,
+        'current_profit': -0.00408133,
+        'current_profit_perc': -0.41,
         'stop_loss': 0.0,
         'initial_stop_loss': 0.0,
         'initial_stop_loss_pct': None,
@@ -93,6 +97,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
         'base_currency': 'BTC',
         'open_date': ANY,
         'open_date_hum': ANY,
+        'open_timestamp': ANY,
         'is_open': ANY,
         'fee_open': ANY,
         'fee_open_cost': ANY,
@@ -112,13 +117,16 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
         'open_order_id': ANY,
         'close_date': None,
         'close_date_hum': None,
+        'close_timestamp': None,
         'open_rate': 1.098e-05,
         'close_rate': None,
         'current_rate': ANY,
         'amount': 91.07468124,
         'stake_amount': 0.001,
         'close_profit': None,
+        'close_profit_perc': None,
         'current_profit': ANY,
+        'current_profit_perc': ANY,
         'stop_loss': 0.0,
         'initial_stop_loss': 0.0,
         'initial_stop_loss_pct': None,
diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py
index 1d68599f2c5..1c0df9903f1 100644
--- a/tests/rpc/test_rpc_apiserver.py
+++ b/tests/rpc/test_rpc_apiserver.py
@@ -420,7 +420,9 @@ def test_api_profit(botclient, mocker, ticker, fee, markets, limit_buy_order, li
                        'best_pair': 'ETH/BTC',
                        'best_rate': 6.2,
                        'first_trade_date': 'just now',
+                       'first_trade_timestamp': ANY,
                        'latest_trade_date': 'just now',
+                       'latest_trade_timestamp': ANY,
                        'profit_all_coin': 6.217e-05,
                        'profit_all_fiat': 0,
                        'profit_all_percent': 6.2,
@@ -497,14 +499,18 @@ def test_api_status(botclient, mocker, ticker, fee, markets):
                         'base_currency': 'BTC',
                         'close_date': None,
                         'close_date_hum': None,
+                        'close_timestamp': None,
                         'close_profit': None,
+                        'close_profit_perc': None,
                         'close_rate': None,
-                        'current_profit': -0.41,
+                        'current_profit': -0.00408133,
+                        'current_profit_perc': -0.41,
                         'current_rate': 1.099e-05,
                         'initial_stop_loss': 0.0,
                         'initial_stop_loss_pct': None,
                         'open_date': ANY,
                         'open_date_hum': 'just now',
+                        'open_timestamp': ANY,
                         'open_order': '(limit buy rem=0.00000000)',
                         'open_rate': 1.098e-05,
                         'pair': 'ETH/BTC',
@@ -609,11 +615,13 @@ def test_api_forcebuy(botclient, mocker, fee):
     assert rc.json == {'amount': 1,
                        'close_date': None,
                        'close_date_hum': None,
+                       'close_timestamp': None,
                        'close_rate': 0.265441,
                        'initial_stop_loss': None,
                        'initial_stop_loss_pct': None,
                        'open_date': ANY,
                        'open_date_hum': 'just now',
+                       'open_timestamp': ANY,
                        'open_rate': 0.245441,
                        'pair': 'ETH/ETH',
                        'stake_amount': 1,
diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py
index b84073dcc86..1d599d13e59 100644
--- a/tests/rpc/test_rpc_telegram.py
+++ b/tests/rpc/test_rpc_telegram.py
@@ -166,8 +166,9 @@ def test_status(default_conf, update, mocker, fee, ticker,) -> None:
             'current_rate': 1.098e-05,
             'amount': 90.99181074,
             'stake_amount': 90.99181074,
-            'close_profit': None,
-            'current_profit': -0.59,
+            'close_profit_perc': None,
+            'current_profit': -0.0059,
+            'current_profit_perc': -0.59,
             'initial_stop_loss': 1.098e-05,
             'stop_loss': 1.099e-05,
             'sell_order_status': None,
diff --git a/tests/test_persistence.py b/tests/test_persistence.py
index 25afed39789..60bf073f84c 100644
--- a/tests/test_persistence.py
+++ b/tests/test_persistence.py
@@ -739,9 +739,11 @@ def test_to_json(default_conf, fee):
                       'is_open': None,
                       'open_date_hum': '2 hours ago',
                       'open_date': trade.open_date.strftime("%Y-%m-%d %H:%M:%S"),
+                      'open_timestamp': int(trade.open_date.timestamp() * 1000),
                       'open_order_id': 'dry_run_buy_12345',
                       'close_date_hum': None,
                       'close_date': None,
+                      'close_timestamp': None,
                       'open_rate': 0.123,
                       'open_rate_requested': None,
                       'open_trade_price': 15.1668225,
@@ -787,8 +789,10 @@ def test_to_json(default_conf, fee):
                       'pair': 'XRP/BTC',
                       'open_date_hum': '2 hours ago',
                       'open_date': trade.open_date.strftime("%Y-%m-%d %H:%M:%S"),
+                      'open_timestamp': int(trade.open_date.timestamp() * 1000),
                       'close_date_hum': 'an hour ago',
                       'close_date': trade.close_date.strftime("%Y-%m-%d %H:%M:%S"),
+                      'close_timestamp': int(trade.close_date.timestamp() * 1000),
                       'open_rate': 0.123,
                       'close_rate': 0.125,
                       'amount': 100.0,


Code review comments:
diff_hunk: @@ -135,9 +135,11 @@ def _rpc_trade_status(self) -> List[Dict[str, Any]]:
                 trade_dict = trade.to_json()
                 trade_dict.update(dict(
                     base_currency=self._freqtrade.config['stake_currency'],
-                    close_profit=fmt_close_profit,
+                    close_profit=trade.close_profit or None,
+                    close_profit_perc=fmt_close_profit,
path: freqtrade/rpc/rpc.py
text: @author:
@user1-1902 
Should this maybe use `close_profit_pct`? (oll other occurances of _perc too, obviously).

that would put it in line with #3377  - and honestly, i find "pct" a better shortcut for percentage than "perc"...

@user2:
> @user1-1902
> Should this maybe use `close_profit_pct`? (oll other occurances of _perc too, obviously).
> 
> that would put it in line with #3377 - and honestly, i find "pct" a better shortcut for percentage than "perc"...

agree, that's the better suffix for these names...