def test_min_roi_reached(default_conf, fee) -> None: # Use list to confirm sequence does not matter min_roi_list = [{20: 0.05, 55: 0.01, 0: 0.1}, {0: 0.1, 20: 0.05, 55: 0.01}] for roi in min_roi_list: default_conf.update({'strategy': 'DefaultStrategy'}) strategy = StrategyResolver.load_strategy(default_conf) strategy.minimal_roi = roi trade = Trade( pair='ETH/BTC', stake_amount=0.001, amount=5, open_date=arrow.utcnow().shift(hours=-1).datetime, fee_open=fee.return_value, fee_close=fee.return_value, exchange='bittrex', open_rate=1, ) assert not strategy.min_roi_reached(trade, 0.02, arrow.utcnow().shift(minutes=-56).datetime) assert strategy.min_roi_reached(trade, 0.12, arrow.utcnow().shift(minutes=-56).datetime) assert not strategy.min_roi_reached(trade, 0.04, arrow.utcnow().shift(minutes=-39).datetime) assert strategy.min_roi_reached(trade, 0.06, arrow.utcnow().shift(minutes=-39).datetime) assert not strategy.min_roi_reached(trade, -0.01, arrow.utcnow().shift(minutes=-1).datetime) assert strategy.min_roi_reached(trade, 0.02, arrow.utcnow().shift(minutes=-1).datetime)
def test_calc_profit(limit_buy_order, limit_sell_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, amount=5, open_rate=0.00001099, fee_open=fee.return_value, fee_close=fee.return_value, exchange='bittrex', ) trade.open_order_id = 'something' trade.update(limit_buy_order) # Buy @ 0.00001099 # Custom closing rate and regular fee rate # Higher than open rate assert trade.calc_profit(rate=0.00001234) == 0.00011753 # Lower than open rate assert trade.calc_profit(rate=0.00000123) == -0.00089086 # Custom closing rate and custom fee rate # Higher than open rate assert trade.calc_profit(rate=0.00001234, fee=0.003) == 0.00011697 # Lower than open rate assert trade.calc_profit(rate=0.00000123, fee=0.003) == -0.00089092 # Test when we apply a Sell order. Sell higher than open rate @ 0.00001173 trade.update(limit_sell_order) assert trade.calc_profit() == 0.00006217 # Test with a custom fee rate on the close trade assert trade.calc_profit(fee=0.003) == 0.00006163
def test_calc_profit_ratio(limit_buy_order, limit_sell_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, amount=5, open_rate=0.00001099, fee_open=fee.return_value, fee_close=fee.return_value, exchange='bittrex', ) trade.open_order_id = 'something' trade.update(limit_buy_order) # Buy @ 0.00001099 # Get percent of profit with a custom rate (Higher than open rate) assert trade.calc_profit_ratio(rate=0.00001234) == 0.11723875 # Get percent of profit with a custom rate (Lower than open rate) assert trade.calc_profit_ratio(rate=0.00000123) == -0.88863828 # Test when we apply a Sell order. Sell higher than open rate @ 0.00001173 trade.update(limit_sell_order) assert trade.calc_profit_ratio() == 0.06201058 # Test with a custom fee rate on the close trade assert trade.calc_profit_ratio(fee=0.003) == 0.06147824
def generate_mock_trade(pair: str, fee: float, is_open: bool, sell_reason: str = SellType.SELL_SIGNAL, min_ago_open: int = None, min_ago_close: int = None, profit_rate: float = 0.9): open_rate = random.random() trade = Trade( pair=pair, stake_amount=0.01, fee_open=fee, fee_close=fee, open_date=datetime.utcnow() - timedelta(minutes=min_ago_open or 200), close_date=datetime.utcnow() - timedelta(minutes=min_ago_close or 30), open_rate=open_rate, is_open=is_open, amount=0.01 / open_rate, exchange='binance', ) trade.recalc_open_trade_value() if not is_open: trade.close(open_rate * profit_rate) trade.sell_reason = sell_reason return trade
def test_fee_updated(fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, fee_open=fee.return_value, open_date=arrow.utcnow().shift(hours=-2).datetime, amount=10, fee_close=fee.return_value, exchange='bittrex', open_rate=1, max_rate=1, ) assert trade.fee_open_currency is None assert not trade.fee_updated('buy') assert not trade.fee_updated('sell') assert not trade.fee_updated('asdf') trade.update_fee(0.15, 'BTC', 0.0075, 'buy') assert trade.fee_updated('buy') assert not trade.fee_updated('sell') assert trade.fee_open_currency is not None assert trade.fee_close_currency is None trade.update_fee(0.15, 'ABC', 0.0075, 'sell') assert trade.fee_updated('buy') assert trade.fee_updated('sell') assert not trade.fee_updated('asfd')
def test_min_roi_reached3(default_conf, fee) -> None: # test for issue #1948 min_roi = {20: 0.07, 30: 0.05, 55: 0.30, } default_conf.update({'strategy': 'DefaultStrategy'}) strategy = StrategyResolver.load_strategy(default_conf) strategy.minimal_roi = min_roi trade = Trade( pair='ETH/BTC', stake_amount=0.001, amount=5, open_date=arrow.utcnow().shift(hours=-1).datetime, fee_open=fee.return_value, fee_close=fee.return_value, exchange='binance', open_rate=1, ) assert not strategy.min_roi_reached(trade, 0.02, arrow.utcnow().shift(minutes=-56).datetime) assert not strategy.min_roi_reached(trade, 0.12, arrow.utcnow().shift(minutes=-56).datetime) assert not strategy.min_roi_reached(trade, 0.04, arrow.utcnow().shift(minutes=-39).datetime) assert strategy.min_roi_reached(trade, 0.071, arrow.utcnow().shift(minutes=-39).datetime) assert not strategy.min_roi_reached(trade, 0.04, arrow.utcnow().shift(minutes=-26).datetime) assert strategy.min_roi_reached(trade, 0.06, arrow.utcnow().shift(minutes=-26).datetime) # Should not trigger with 20% profit since after 55 minutes only 30% is active. assert not strategy.min_roi_reached(trade, 0.20, arrow.utcnow().shift(minutes=-2).datetime) assert strategy.min_roi_reached(trade, 0.31, arrow.utcnow().shift(minutes=-2).datetime)
def test_update_market_order(market_buy_order, market_sell_order, fee, caplog): trade = Trade( id=1, pair='ETH/BTC', stake_amount=0.001, fee_open=fee.return_value, fee_close=fee.return_value, exchange='bittrex', ) trade.open_order_id = 'something' trade.update(market_buy_order) assert trade.open_order_id is None assert trade.open_rate == 0.00004099 assert trade.close_profit is None assert trade.close_date is None assert log_has( "MARKET_BUY has been fulfilled for Trade(id=1, " "pair=ETH/BTC, amount=91.99181073, open_rate=0.00004099, open_since=closed).", caplog) caplog.clear() trade.open_order_id = 'something' trade.update(market_sell_order) assert trade.open_order_id is None assert trade.close_rate == 0.00004173 assert trade.close_profit == 0.01297561 assert trade.close_date is not None assert log_has( "MARKET_SELL has been fulfilled for Trade(id=1, " "pair=ETH/BTC, amount=91.99181073, open_rate=0.00004099, open_since=closed).", caplog)
def _get_sell_trade_entry( self, pair: str, buy_row: DataFrame, partial_ticker: List, trade_count_lock: Dict, args: Dict) -> Optional[Tuple]: stake_amount = args['stake_amount'] max_open_trades = args.get('max_open_trades', 0) trade = Trade( open_rate=buy_row.close + self.slippage, #implement slippage 0.01 for buy_row open_date=buy_row.date, stake_amount=stake_amount, amount=stake_amount / buy_row.open, fee=exchange.get_fee() ) # calculate win/lose forwards from buy point for sell_row in partial_ticker: if max_open_trades > 0: # Increase trade_count_lock for every iteration trade_count_lock[sell_row.date] = trade_count_lock.get(sell_row.date, 0) + 1 buy_signal = sell_row.buy #implement slippage 0.01 for sell_row if self.analyze.should_sell(trade, sell_row.close - self.slippage, sell_row.date, buy_signal, sell_row.sell): return \ sell_row, \ ( pair, trade.calc_profit_percent(rate=sell_row.close), trade.calc_profit(rate=sell_row.close), (sell_row.date - buy_row.date).seconds // 60 ), \ sell_row.date return None
def test_adjust_min_max_rates(fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, amount=5, fee_open=fee.return_value, fee_close=fee.return_value, exchange='bittrex', open_rate=1, ) trade.adjust_min_max_rates(trade.open_rate) assert trade.max_rate == 1 assert trade.min_rate == 1 # check min adjusted, max remained trade.adjust_min_max_rates(0.96) assert trade.max_rate == 1 assert trade.min_rate == 0.96 # check max adjusted, min remains trade.adjust_min_max_rates(1.05) assert trade.max_rate == 1.05 assert trade.min_rate == 0.96 # current rate "in the middle" - no adjustment trade.adjust_min_max_rates(1.03) assert trade.max_rate == 1.05 assert trade.min_rate == 0.96
def test_trade_close(limit_buy_order, limit_sell_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, open_rate=0.01, amount=5, is_open=True, fee_open=fee.return_value, fee_close=fee.return_value, open_date=arrow.Arrow(2020, 2, 1, 15, 5, 1).datetime, exchange='bittrex', ) assert trade.close_profit is None assert trade.close_date is None assert trade.is_open is True trade.close(0.02) assert trade.is_open is False assert trade.close_profit == 0.99002494 assert trade.close_date is not None new_date = arrow.Arrow(2020, 2, 2, 15, 6, 1).datetime, assert trade.close_date != new_date # Close should NOT update close_date if the trade has been closed already assert trade.is_open is False trade.close_date = new_date trade.close(0.02) assert trade.close_date == new_date
def test_backtest(conf, pairs, mocker): trades = [] mocker.patch.dict('freqtrade.main._CONF', conf) for pair in pairs: with open('freqtrade/tests/testdata/'+pair+'.json') as data_file: data = json.load(data_file) mocker.patch('freqtrade.analyze.get_ticker_history', return_value=data) mocker.patch('arrow.utcnow', return_value=arrow.get('2017-08-20T14:50:00')) ticker = analyze_ticker(pair) # for each buy point for index, row in ticker[ticker.buy == 1].iterrows(): trade = Trade( open_rate=row['close'], open_date=arrow.get(row['date']).datetime, amount=1, ) # calculate win/lose forwards from buy point for index2, row2 in ticker[index:].iterrows(): if should_sell(trade, row2['close'], arrow.get(row2['date']).datetime): current_profit = (row2['close'] - trade.open_rate) / trade.open_rate trades.append((pair, current_profit, index2 - index)) break labels = ['currency', 'profit', 'duration'] results = DataFrame.from_records(trades, columns=labels) print('====================== BACKTESTING REPORT ================================') for pair in pairs: print('For currency {}:'.format(pair)) print_results(results[results.currency == pair]) print('TOTAL OVER ALL TRADES:') print_results(results)
def test_min_roi_reached2(default_conf, fee) -> None: # test with ROI raising after last interval min_roi_list = [ { 20: 0.07, 30: 0.05, 55: 0.30, 0: 0.1 }, { 0: 0.1, 20: 0.07, 30: 0.05, 55: 0.30 }, ] for roi in min_roi_list: default_conf.update({'strategy': 'DefaultStrategy'}) strategy = StrategyResolver.load_strategy(default_conf) strategy.minimal_roi = roi trade = Trade( pair='ETH/BTC', stake_amount=0.001, amount=5, open_date=arrow.utcnow().shift(hours=-1).datetime, fee_open=fee.return_value, fee_close=fee.return_value, exchange='bittrex', open_rate=1, ) assert not strategy.min_roi_reached( trade, 0.02, arrow.utcnow().shift(minutes=-56).datetime) assert strategy.min_roi_reached( trade, 0.12, arrow.utcnow().shift(minutes=-56).datetime) assert not strategy.min_roi_reached( trade, 0.04, arrow.utcnow().shift(minutes=-39).datetime) assert strategy.min_roi_reached( trade, 0.071, arrow.utcnow().shift(minutes=-39).datetime) assert not strategy.min_roi_reached( trade, 0.04, arrow.utcnow().shift(minutes=-26).datetime) assert strategy.min_roi_reached( trade, 0.06, arrow.utcnow().shift(minutes=-26).datetime) # Should not trigger with 20% profit since after 55 minutes only 30% is active. assert not strategy.min_roi_reached( trade, 0.20, arrow.utcnow().shift(minutes=-2).datetime) assert strategy.min_roi_reached( trade, 0.31, arrow.utcnow().shift(minutes=-2).datetime)
def backtest(backtest_conf, backdata, mocker): trades = [] exchange._API = Bittrex({'key': '', 'secret': ''}) mocked_history = mocker.patch('freqtrade.analyze.get_ticker_history') mocker.patch.dict('freqtrade.main._CONF', backtest_conf) mocker.patch('arrow.utcnow', return_value=arrow.get('2017-08-20T14:50:00')) for pair, pair_data in backdata.items(): mocked_history.return_value = pair_data ticker = analyze_ticker(pair)[['close', 'date', 'buy']].copy() # for each buy point for row in ticker[ticker.buy == 1].itertuples(index=True): trade = Trade(open_rate=row.close, open_date=row.date, amount=1, fee=exchange.get_fee() * 2) # calculate win/lose forwards from buy point for row2 in ticker[row.Index:].itertuples(index=True): if should_sell(trade, row2.close, row2.date): current_profit = trade.calc_profit(row2.close) trades.append( (pair, current_profit, row2.Index - row.Index)) break labels = ['currency', 'profit', 'duration'] results = DataFrame.from_records(trades, columns=labels) return results
def backtest(backtest_conf, processed, mocker): trades = [] exchange._API = Bittrex({'key': '', 'secret': ''}) mocker.patch.dict('freqtrade.main._CONF', backtest_conf) for pair, pair_data in processed.items(): pair_data['buy'] = 0 pair_data['sell'] = 0 ticker = populate_sell_trend(populate_buy_trend(pair_data)) # for each buy point for row in ticker[ticker.buy == 1].itertuples(index=True): trade = Trade(open_rate=row.close, open_date=row.date, amount=backtest_conf['stake_amount'], fee=exchange.get_fee() * 2) # calculate win/lose forwards from buy point for row2 in ticker[row.Index:].itertuples(index=True): if min_roi_reached(trade, row2.close, row2.date) or row2.sell == 1: current_profit = trade.calc_profit(row2.close) trades.append( (pair, current_profit, row2.Index - row.Index)) break labels = ['currency', 'profit', 'duration'] return DataFrame.from_records(trades, columns=labels)
def test_clean_dry_run_db(default_conf, fee): # Simulate dry_run entries trade = Trade( pair='ETH/BTC', stake_amount=0.001, amount=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', open_order_id='dry_run_buy_12345' ) Trade.session.add(trade) trade = Trade( pair='ETC/BTC', stake_amount=0.001, amount=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', open_order_id='dry_run_sell_12345' ) Trade.session.add(trade) # Simulate prod entry trade = Trade( pair='ETC/BTC', stake_amount=0.001, amount=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', open_order_id='prod_buy_12345' ) Trade.session.add(trade) # We have 3 entries: 2 dry_run, 1 prod assert len(Trade.query.filter(Trade.open_order_id.isnot(None)).all()) == 3 clean_dry_run_db() # We have now only the prod assert len(Trade.query.filter(Trade.open_order_id.isnot(None)).all()) == 1
def test_api_performance(botclient, fee): ftbot, client = botclient patch_get_signal(ftbot) trade = Trade( pair='LTC/ETH', amount=1, exchange='binance', stake_amount=1, open_rate=0.245441, open_order_id="123456", is_open=False, fee_close=fee.return_value, fee_open=fee.return_value, close_rate=0.265441, ) trade.close_profit = trade.calc_profit_ratio() trade.close_profit_abs = trade.calc_profit() Trade.query.session.add(trade) trade = Trade( pair='XRP/ETH', amount=5, stake_amount=1, exchange='binance', open_rate=0.412, open_order_id="123456", is_open=False, fee_close=fee.return_value, fee_open=fee.return_value, close_rate=0.391 ) trade.close_profit = trade.calc_profit_ratio() trade.close_profit_abs = trade.calc_profit() Trade.query.session.add(trade) Trade.commit() rc = client_get(client, f"{BASE_URI}/performance") assert_response(rc) assert len(rc.json()) == 2 assert rc.json() == [{'count': 1, 'pair': 'LTC/ETH', 'profit': 7.61, 'profit_pct': 7.61, 'profit_ratio': 0.07609203, 'profit_abs': 0.01872279}, {'count': 1, 'pair': 'XRP/ETH', 'profit': -5.57, 'profit_pct': -5.57, 'profit_ratio': -0.05570419, 'profit_abs': -0.1150375}]
def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, trailing, custom, profit2, adjusted2, expected2, custom_stop) -> None: default_conf.update({'strategy': 'DefaultStrategy'}) strategy = StrategyResolver.load_strategy(default_conf) trade = Trade( pair='ETH/BTC', stake_amount=0.01, amount=1, open_date=arrow.utcnow().shift(hours=-1).datetime, fee_open=fee.return_value, fee_close=fee.return_value, exchange='binance', open_rate=1, ) trade.adjust_min_max_rates(trade.open_rate) strategy.trailing_stop = trailing strategy.trailing_stop_positive = -0.05 strategy.use_custom_stoploss = custom original_stopvalue = strategy.custom_stoploss if custom_stop: strategy.custom_stoploss = custom_stop now = arrow.utcnow().datetime sl_flag = strategy.stop_loss_reached(current_rate=trade.open_rate * (1 + profit), trade=trade, current_time=now, current_profit=profit, force_stoploss=0, high=None, dataframe=None) assert isinstance(sl_flag, SellCheckTuple) assert sl_flag.sell_type == expected if expected == SellType.NONE: assert sl_flag.sell_flag is False else: assert sl_flag.sell_flag is True assert round(trade.stop_loss, 2) == adjusted sl_flag = strategy.stop_loss_reached(current_rate=trade.open_rate * (1 + profit2), trade=trade, current_time=now, current_profit=profit2, force_stoploss=0, high=None, dataframe=None) assert sl_flag.sell_type == expected2 if expected2 == SellType.NONE: assert sl_flag.sell_flag is False else: assert sl_flag.sell_flag is True assert round(trade.stop_loss, 2) == adjusted2 strategy.custom_stoploss = original_stopvalue
def test_api_forcebuy(botclient, mocker, fee): ftbot, client = botclient rc = client_post(client, f"{BASE_URI}/forcebuy", data='{"pair": "ETH/BTC"}') assert_response(rc, 502) assert rc.json == { "error": "Error querying _forcebuy: Forcebuy not enabled." } # enable forcebuy ftbot.config["forcebuy_enable"] = True fbuy_mock = MagicMock(return_value=None) mocker.patch("freqtrade.rpc.RPC._rpc_forcebuy", fbuy_mock) rc = client_post(client, f"{BASE_URI}/forcebuy", data='{"pair": "ETH/BTC"}') assert_response(rc) assert rc.json == {"status": "Error buying pair ETH/BTC."} # Test creating trae fbuy_mock = MagicMock(return_value=Trade( pair='ETH/ETH', amount=1, exchange='bittrex', stake_amount=1, open_rate=0.245441, open_order_id="123456", open_date=datetime.utcnow(), is_open=False, fee_close=fee.return_value, fee_open=fee.return_value, close_rate=0.265441, )) mocker.patch("freqtrade.rpc.RPC._rpc_forcebuy", fbuy_mock) rc = client_post(client, f"{BASE_URI}/forcebuy", data='{"pair": "ETH/BTC"}') assert_response(rc) assert rc.json == { 'amount': 1, 'close_date': None, 'close_date_hum': None, 'close_rate': 0.265441, 'initial_stop_loss': None, 'initial_stop_loss_pct': None, 'open_date': ANY, 'open_date_hum': 'just now', 'open_rate': 0.245441, 'pair': 'ETH/ETH', 'stake_amount': 1, 'stop_loss': None, 'stop_loss_pct': None, 'trade_id': None }
def test_stoploss_reinitialization(default_conf, fee): init(default_conf['db_url']) trade = Trade( pair='ETH/BTC', stake_amount=0.001, fee_open=fee.return_value, open_date=arrow.utcnow().shift(hours=-2).datetime, amount=10, fee_close=fee.return_value, exchange='bittrex', open_rate=1, max_rate=1, ) trade.adjust_stop_loss(trade.open_rate, 0.05, True) assert trade.stop_loss == 0.95 assert trade.stop_loss_pct == -0.05 assert trade.initial_stop_loss == 0.95 assert trade.initial_stop_loss_pct == -0.05 Trade.session.add(trade) # Lower stoploss Trade.stoploss_reinitialization(0.06) trades = Trade.get_open_trades() assert len(trades) == 1 trade_adj = trades[0] assert trade_adj.stop_loss == 0.94 assert trade_adj.stop_loss_pct == -0.06 assert trade_adj.initial_stop_loss == 0.94 assert trade_adj.initial_stop_loss_pct == -0.06 # Raise stoploss Trade.stoploss_reinitialization(0.04) trades = Trade.get_open_trades() assert len(trades) == 1 trade_adj = trades[0] assert trade_adj.stop_loss == 0.96 assert trade_adj.stop_loss_pct == -0.04 assert trade_adj.initial_stop_loss == 0.96 assert trade_adj.initial_stop_loss_pct == -0.04 # Trailing stoploss (move stoplos up a bit) trade.adjust_stop_loss(1.02, 0.04) assert trade_adj.stop_loss == 0.9792 assert trade_adj.initial_stop_loss == 0.96 Trade.stoploss_reinitialization(0.04) trades = Trade.get_open_trades() assert len(trades) == 1 trade_adj = trades[0] # Stoploss should not change in this case. assert trade_adj.stop_loss == 0.9792 assert trade_adj.stop_loss_pct == -0.04 assert trade_adj.initial_stop_loss == 0.96 assert trade_adj.initial_stop_loss_pct == -0.04
def test_api_performance(botclient, mocker, ticker, fee): ftbot, client = botclient patch_get_signal(ftbot, (True, False)) trade = Trade( pair='LTC/ETH', amount=1, exchange='binance', stake_amount=1, open_rate=0.245441, open_order_id="123456", is_open=False, fee_close=fee.return_value, fee_open=fee.return_value, close_rate=0.265441, ) trade.close_profit = trade.calc_profit_percent() Trade.session.add(trade) trade = Trade(pair='XRP/ETH', amount=5, stake_amount=1, exchange='binance', open_rate=0.412, open_order_id="123456", is_open=False, fee_close=fee.return_value, fee_open=fee.return_value, close_rate=0.391) trade.close_profit = trade.calc_profit_percent() Trade.session.add(trade) Trade.session.flush() rc = client_get(client, f"{BASE_URI}/performance") assert_response(rc) assert len(rc.json) == 2 assert rc.json == [{ 'count': 1, 'pair': 'LTC/ETH', 'profit': 7.61 }, { 'count': 1, 'pair': 'XRP/ETH', 'profit': -5.57 }]
def test_clean_dry_run_db(default_conf): init(default_conf, create_engine('sqlite://')) # Simulate dry_run entries trade = Trade( pair='BTC_ETH', stake_amount=0.001, amount=123.0, fee=0.0025, open_rate=0.123, exchange='BITTREX', open_order_id='dry_run_buy_12345' ) Trade.session.add(trade) trade = Trade( pair='BTC_ETC', stake_amount=0.001, amount=123.0, fee=0.0025, open_rate=0.123, exchange='BITTREX', open_order_id='dry_run_sell_12345' ) Trade.session.add(trade) # Simulate prod entry trade = Trade( pair='BTC_ETC', stake_amount=0.001, amount=123.0, fee=0.0025, open_rate=0.123, exchange='BITTREX', open_order_id='prod_buy_12345' ) Trade.session.add(trade) # We have 3 entries: 2 dry_run, 1 prod assert len(Trade.query.filter(Trade.open_order_id.isnot(None)).all()) == 3 clean_dry_run_db() # We have now only the prod assert len(Trade.query.filter(Trade.open_order_id.isnot(None)).all()) == 1
def create_mock_trades(fee): """ Create some fake trades ... """ # Simulate dry_run entries trade = Trade( pair='ETH/BTC', stake_amount=0.001, amount=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', open_order_id='dry_run_buy_12345' ) Trade.session.add(trade) trade = Trade( pair='ETC/BTC', stake_amount=0.001, amount=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, close_rate=0.128, close_profit=0.005, exchange='bittrex', is_open=False, open_order_id='dry_run_sell_12345' ) Trade.session.add(trade) # Simulate prod entry trade = Trade( pair='ETC/BTC', stake_amount=0.001, amount=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', open_order_id='prod_buy_12345' ) Trade.session.add(trade)
def test_update_invalid_order(limit_buy_order): trade = Trade( pair='BTC_ETH', stake_amount=1.00, fee=0.1, exchange=Exchanges.BITTREX, ) limit_buy_order['type'] = 'invalid' with pytest.raises(ValueError, match=r'Unknown order type'): trade.update(limit_buy_order)
def test_update_invalid_order(limit_buy_order): trade = Trade( pair='ETH/BTC', stake_amount=1.00, fee_open=0.1, fee_close=0.1, exchange='bittrex', ) limit_buy_order['type'] = 'invalid' with pytest.raises(ValueError, match=r'Unknown order type'): trade.update(limit_buy_order)
def open_trade(): return Trade(pair='ETH/BTC', open_rate=0.00001099, exchange='bittrex', open_order_id='123456789', amount=90.99181073, fee_open=0.0, fee_close=0.0, stake_amount=1, open_date=arrow.utcnow().shift(minutes=-601).datetime, is_open=True)
def test_calc_close_trade_price_exception(limit_buy_order): trade = Trade( pair='BTC_ETH', stake_amount=0.001, fee=0.0025, exchange=Exchanges.BITTREX, ) trade.open_order_id = 'something' trade.update(limit_buy_order) assert trade.calc_close_trade_price() == 0.0
def test_calc_close_trade_price_exception(limit_buy_order, fee): trade = Trade( pair='ETH/BTC', stake_amount=0.001, fee_open=fee.return_value, fee_close=fee.return_value, exchange='bittrex', ) trade.open_order_id = 'something' trade.update(limit_buy_order) assert trade.calc_close_trade_price() == 0.0
def execute_buy(self, pair: str, stake_amount: float) -> bool: """ Executes a limit buy for the given pair :param pair: pair for which we want to create a LIMIT_BUY :return: None """ pair_s = pair.replace('_', '/') pair_url = self.exchange.get_pair_detail_url(pair) stake_currency = self.config['stake_currency'] fiat_currency = self.config.get('fiat_display_currency', None) # Calculate amount buy_limit = self.get_target_bid(pair, self.exchange.get_ticker(pair)) min_stake_amount = self._get_min_pair_stake_amount(pair_s, buy_limit) if min_stake_amount is not None and min_stake_amount > stake_amount: logger.warning( f'Can\'t open a new trade for {pair_s}: stake amount' f' is too small ({stake_amount} < {min_stake_amount})') return False amount = stake_amount / buy_limit order_id = self.exchange.buy(pair, buy_limit, amount)['id'] self.rpc.send_msg({ 'type': RPCMessageType.BUY_NOTIFICATION, 'exchange': self.exchange.name.capitalize(), 'pair': pair_s, 'market_url': pair_url, 'limit': buy_limit, 'stake_amount': stake_amount, 'stake_currency': stake_currency, 'fiat_currency': fiat_currency }) # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker') trade = Trade(pair=pair, stake_amount=stake_amount, amount=amount, fee_open=fee, fee_close=fee, open_rate=buy_limit, open_rate_requested=buy_limit, open_date=datetime.utcnow(), exchange=self.exchange.id, open_order_id=order_id, strategy=self.strategy.get_strategy_name(), ticker_interval=constants.TICKER_INTERVAL_MINUTES[ self.config['ticker_interval']]) Trade.session.add(trade) Trade.session.flush() return True
def test_update_with_bittrex(limit_buy_order, limit_sell_order, fee): """ On this test we will buy and sell a crypto currency. Buy - Buy: 90.99181073 Crypto at 0.00001099 BTC (90.99181073*0.00001099 = 0.0009999 BTC) - Buying fee: 0.25% - Total cost of buy trade: 0.001002500 BTC ((90.99181073*0.00001099) + ((90.99181073*0.00001099)*0.0025)) Sell - Sell: 90.99181073 Crypto at 0.00001173 BTC (90.99181073*0.00001173 = 0,00106733394 BTC) - Selling fee: 0.25% - Total cost of sell trade: 0.001064666 BTC ((90.99181073*0.00001173) - ((90.99181073*0.00001173)*0.0025)) Profit/Loss: +0.000062166 BTC (Sell:0.001064666 - Buy:0.001002500) Profit/Loss percentage: 0.0620 ((0.001064666/0.001002500)-1 = 6.20%) :param limit_buy_order: :param limit_sell_order: :return: """ trade = Trade( pair='ETH/BTC', stake_amount=0.001, fee_open=fee.return_value, fee_close=fee.return_value, exchange='bittrex', ) assert trade.open_order_id is None assert trade.open_rate is None assert trade.close_profit is None assert trade.close_date is None trade.open_order_id = 'something' trade.update(limit_buy_order) assert trade.open_order_id is None assert trade.open_rate == 0.00001099 assert trade.close_profit is None assert trade.close_date is None trade.open_order_id = 'something' trade.update(limit_sell_order) assert trade.open_order_id is None assert trade.close_rate == 0.00001173 assert trade.close_profit == 0.06201057 assert trade.close_date is not None
def _get_sell_trade_entry(self, pair: str, buy_row: DataFrame, partial_ticker: List, trade_count_lock: Dict, args: Dict) -> Optional[BacktestResult]: stake_amount = args['stake_amount'] max_open_trades = args.get('max_open_trades', 0) trade = Trade(open_rate=buy_row.close, open_date=buy_row.date, stake_amount=stake_amount, amount=stake_amount / buy_row.open, fee_open=self.fee, fee_close=self.fee) # calculate win/lose forwards from buy point for sell_row in partial_ticker: if max_open_trades > 0: # Increase trade_count_lock for every iteration trade_count_lock[sell_row.date] = trade_count_lock.get( sell_row.date, 0) + 1 buy_signal = sell_row.buy if self.analyze.should_sell(trade, sell_row.close, sell_row.date, buy_signal, sell_row.sell): return BacktestResult( pair=pair, profit_percent=trade.calc_profit_percent( rate=sell_row.close), profit_abs=trade.calc_profit(rate=sell_row.close), open_time=buy_row.date, close_time=sell_row.date, trade_duration=(sell_row.date - buy_row.date).seconds // 60, open_index=buy_row.Index, close_index=sell_row.Index, open_at_end=False) if partial_ticker: # no sell condition found - trade stil open at end of backtest period sell_row = partial_ticker[-1] btr = BacktestResult( pair=pair, profit_percent=trade.calc_profit_percent(rate=sell_row.close), profit_abs=trade.calc_profit(rate=sell_row.close), open_time=buy_row.date, close_time=sell_row.date, trade_duration=(sell_row.date - buy_row.date).seconds // 60, open_index=buy_row.Index, close_index=sell_row.Index, open_at_end=True) logger.debug('Force_selling still open trade %s with %s perc - %s', btr.pair, btr.profit_percent, btr.profit_abs) return btr return None