def create_dummy_data(influx_database: InfluxDBClient): storage = OrderInnoDbStorage(influx_database, 'test_orders') storage.save_order(Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847da'), UUID('99fd2706-8baf-433b-82eb-8c7fada847da'), DUMMY_MARKET, DIRECTION_BUY, datetime.datetime(2017, 11, 26, 10, 11, 12, tzinfo=datetime.timezone.utc), BTC_USD_PAIR, ORDER_TYPE_LIMIT, Decimal('1'), Decimal('8000'), 'aaa-id-from-market', ORDER_STATUS_OPEN )) storage.save_order(Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847db'), UUID('99fd2706-8baf-433b-82eb-8c7fada847db'), DUMMY_MARKET, DIRECTION_SELL, datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc), BTC_USD_PAIR, ORDER_TYPE_LIMIT, Decimal('2'), Decimal('9000'), 'bbb-id-from-market', ORDER_STATUS_CLOSED ))
def place_order(self, order: Order) -> Order: assert order.market_name == self.name logging.info('Placing order: {}'.format(order)) market = self._format_market_pair(order.pair) self._validate_minimal_order(order) if order.type == ORDER_TYPE_MARKET: raise NotImplementedError( 'Bittrex does not support MARKET orders.') elif order.type == ORDER_TYPE_LIMIT: if order.is_sell(): result = self._client_v1.sell_limit(market, float(order.quantity), float(order.rate)) elif order.is_buy(): result = self._client_v1.buy_limit(market, float(order.quantity), float(order.rate)) else: raise ValueError('Unknown order direction: {}'.format( order._direction)) self._validate_result(result) order.set_id_on_market(result['result']['uuid']) return order else: raise ValueError('Unknown order type: {}'.format(order.type))
def place_order(self, order: Order) -> Order: fee = self._calculate_fee(order) self._initialize_balances(order.pair) if order.is_sell(): self._process_sell(fee, order) elif order.is_buy(): self._process_buy(fee, order) order.close(order.created_at) return order
def cancel(self, market: Market, order: Order, canceled_at: datetime.datetime): try: market.cancel_order(order.id_on_market) except MarketException as e: logger.error('Order "{}" cancelling failed: Error: "{}"!'.format( order.order_id, e)) return order.cancel(canceled_at) self._order_storage.save_order(order) logger.info('Order "{}" has been CANCELED!'.format(order.order_id))
def _create_order_from_serialized( row: Dict[str, Union[str, int, float, bool]]) -> Order: pair_data = str(row[ORDER_FIELD_PAIR]).split('_') closed_at = None if ORDER_FIELD_CLOSED_AT in row and row[ ORDER_FIELD_CLOSED_AT] is not None: closed_at = dateutil.parser.parse(str( row[ORDER_FIELD_CLOSED_AT])).replace( tzinfo=datetime.timezone.utc) canceled_at = None if ORDER_FIELD_CANCELED_AT in row and row[ ORDER_FIELD_CANCELED_AT] is not None: canceled_at = dateutil.parser.parse( str(row[ORDER_FIELD_CANCELED_AT])).replace( tzinfo=datetime.timezone.utc) return Order( UUID(str(row[ORDER_FIELD_ORDER_ID])), UUID(str(row[ORDER_FIELD_STRATEGY_RUN_ID])), str(row[ORDER_FIELD_MARKET]), str(row[ORDER_FIELD_DIRECTION]), dateutil.parser.parse(str(row['time'])).replace(tzinfo=datetime.timezone.utc), Pair(pair_data[0], pair_data[1]), str(row[ORDER_FIELD_TYPE]), Decimal(row[ORDER_FIELD_QUANTITY]), Decimal(row[ORDER_FIELD_RATE]) if ORDER_FIELD_RATE in row and row[ORDER_FIELD_RATE] is not None else None, str(row[ORDER_FIELD_ID_ON_MARKET]) \ if ORDER_FIELD_ID_ON_MARKET in row and row[ORDER_FIELD_ID_ON_MARKET] \ else None, str(row[ORDER_FIELD_STATUS]), closed_at, canceled_at )
def test_find_last_order(influx_database: InfluxDBClient): storage = OrderInnoDbStorage(influx_database, 'test_orders') order = storage.find_last_order(DUMMY_MARKET, BTC_USD_PAIR) assert order is None storage.save_order(DUMMY_ORDER) order = storage.find_last_order(DUMMY_MARKET, BTC_USD_PAIR) assert str(order.order_id) == '16fd2706-8baf-433b-82eb-8c7fada847da' later_order = Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847db'), UUID('99fd2706-8baf-433b-82eb-8c7fada847da'), DUMMY_MARKET, DIRECTION_BUY, datetime.datetime(2017, 11, 26, 10, 11, 13, tzinfo=datetime.timezone.utc), BTC_USD_PAIR, ORDER_TYPE_LIMIT, Decimal('1'), Decimal('8000'), 'aaa-id-from-market' ) storage.save_order(later_order) order = storage.find_last_order(DUMMY_MARKET, BTC_USD_PAIR) assert str(order.order_id) == '16fd2706-8baf-433b-82eb-8c7fada847db'
def _trade_on_signal(self, market: Market) -> None: logger.info('Checking trade on signal: "{}".'.format( self._last_signal)) try: if self._last_signal.is_buy(): self._cancel_open_order(market, DIRECTION_SELL) if self._does_trade_worth_it(market): order = Order( uuid.uuid4(), self._strategy_run.strategy_run_id, market.name, DIRECTION_BUY, self._datetime_factory.now(), self._strategy_run.pair, ORDER_TYPE_LIMIT, market.calculate_maximal_amount_to_buy( self._strategy_run.pair, self._last_signal.average_price), self._last_signal.average_price) self._order_facade.create(market, order) self._last_signal = None elif self._last_signal.is_sell(): self._cancel_open_order(market, DIRECTION_BUY) if self._does_trade_worth_it(market): order = Order( uuid.uuid4(), self._strategy_run.strategy_run_id, market.name, DIRECTION_SELL, self._datetime_factory.now(), self._strategy_run.pair, ORDER_TYPE_LIMIT, market.calculate_maximal_amount_to_sell( self._strategy_run.pair), self._last_signal.average_price) self._order_facade.create(market, order) self._last_signal = None else: raise ValueError('Unknown signal: "{}"'.format( self._last_signal)) # pragma: no cover except NotEnoughBalanceToPerformOrderException as e: # Intentionally, this strategy does not need state of order, # just ignores buy/sell and waits for next signal. logger.warning(str(e)) self._last_signal = None
def _crate_serialized_order(pair: Pair, market_name: str, created_at: datetime.datetime): return serialize_order( Order( uuid.uuid4(), uuid.UUID('99fd2706-8baf-433b-82eb-8c7fada847da'), market_name, DIRECTION_SELL, created_at, pair, ORDER_TYPE_LIMIT, Decimal('1'), Decimal('11000') ))
def create_order(direction: str = DIRECTION_BUY, quantity: Decimal = Decimal('1'), rate: Decimal = Decimal('10000'), pair: Pair = BTC_USD_PAIR) -> Order: return Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847da'), UUID('99fd2706-8baf-433b-82eb-8c7fada847da'), 'dummy_market_name', direction, datetime.datetime(2017, 11, 26, 10, 11, 12, tzinfo=datetime.timezone.utc), pair, ORDER_TYPE_LIMIT, quantity, rate)
def create_order(self, market: Market, direction: str): current_price = market.get_current_price(self._strategy_run.pair) logger.info(direction.upper() + 'ING at price: ' + str(current_price)) order = Order( uuid.uuid4(), self._strategy_run.strategy_run_id, market.name, direction, self._datetime_factory.now(), self._strategy_run.pair, ORDER_TYPE_LIMIT, market.calculate_maximal_amount_to_buy(self._strategy_run.pair, current_price) \ if direction is DIRECTION_BUY \ else market.calculate_maximal_amount_to_sell(self._strategy_run.pair), current_price ) self._order_facade.create(market, order)
def test_order_export_import(): pair = Pair('USD', 'BTC') order = Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847da'), UUID('99fd2706-8baf-433b-82eb-8c7fada847da'), DUMMY_MARKET, DIRECTION_BUY, datetime.datetime(2017, 11, 26, 10, 11, 12, tzinfo=datetime.timezone.utc), pair, ORDER_TYPE_LIMIT, Decimal('1'), Decimal('8000'), 'aaa-id-from-market' ) storage = flexmock() storage.should_receive('find_by').and_return([order]).once() storage.should_receive('save_order').once() exporter = OrderExporter(storage) file_name = os.path.dirname(__file__) + '_orders.json' exporter.export_to_file(file_name, 'dummy_market', pair) expected = [{ "order_id": "16fd2706-8baf-433b-82eb-8c7fada847da", "strategy_run_id": "99fd2706-8baf-433b-82eb-8c7fada847da", "market": "dummy_market_name", "direction": "buy", "created_at": "2017-11-26T10:11:12+00:00", "pair": "USD_BTC", "type": "limit", "quantity": "1", "rate": "8000", "id_on_market": "aaa-id-from-market", "status": "open", "closed_at": None, "canceled_at": None }] with open(file_name) as json_file: assert json.load(json_file) == expected exporter.import_from_file(file_name) os.remove(file_name)
from coinrat.domain.pair import Pair from coinrat.domain.market import Market from coinrat.domain.order import ORDER_TYPE_LIMIT, Order, OrderMarketInfo, DIRECTION_BUY, DIRECTION_SELL, \ NotEnoughBalanceToPerformOrderException, ORDER_STATUS_CLOSED, ORDER_STATUS_OPEN, OrderStorage from coinrat.order_facade import OrderFacade from coinrat_double_crossover_strategy.strategy import DoubleCrossoverStrategy from coinrat.event.event_emitter import EventEmitter DUMMY_MARKET_NAME = 'dummy_market' BTC_USD_PAIR = Pair('USD', 'BTC') STRATEGY_RUN_ID = UUID('99fd2706-8baf-433b-82eb-8c7fada847da') DUMMY_CLOSED_ORDER = Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847da'), STRATEGY_RUN_ID, DUMMY_MARKET_NAME, DIRECTION_BUY, datetime.datetime(2017, 11, 26, 10, 11, 12, tzinfo=datetime.timezone.utc), BTC_USD_PAIR, ORDER_TYPE_LIMIT, Decimal('1'), Decimal('8000'), 'aaa-id-from-market', ORDER_STATUS_CLOSED, datetime.datetime(2017, 11, 26, 10, 11, 12, tzinfo=datetime.timezone.utc)) DUMMY_OPEN_ORDER = Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847db'), STRATEGY_RUN_ID, DUMMY_MARKET_NAME, DIRECTION_BUY, datetime.datetime(2017, 11, 26, 10, 11, 12, tzinfo=datetime.timezone.utc), BTC_USD_PAIR, ORDER_TYPE_LIMIT, Decimal('1'), Decimal('8000'), 'aaa-id-from-market') STRATEGY_RUN = StrategyRun( STRATEGY_RUN_ID, datetime.datetime(2017, 11, 26, 10, 11, 12, tzinfo=datetime.timezone.utc), BTC_USD_PAIR, [], '', { 'long_average_interval': 60 * 60, 'short_average_interval': 15 * 60,
from flexmock import flexmock, Mock from coinrat.domain.pair import Pair from coinrat.domain.market import MarketException from coinrat.domain.order import Order, ORDER_TYPE_LIMIT, ORDER_TYPE_MARKET, DIRECTION_BUY, DIRECTION_SELL, \ NotEnoughBalanceToPerformOrderException from coinrat_bittrex.market import BittrexMarket from coinrat_bittrex.test.fixtures import MARKET_USDT_BTC_DATA, DUMMY_ORDER_ID_ON_MARKET, OPEN_ORDER, CLOSED_ORDER BTC_USD_PAIR = Pair('USD', 'BTC') DUMMY_LIMIT_BUY_ORDER = Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847da'), UUID('99fd2706-8baf-433b-82eb-8c7fada847da'), 'bittrex', DIRECTION_BUY, datetime.datetime(2017, 11, 26, 10, 11, 12, tzinfo=datetime.timezone.utc), BTC_USD_PAIR, ORDER_TYPE_LIMIT, Decimal('1'), Decimal('8000') ) DUMMY_MARKET_BUY_ORDER = Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847db'), UUID('99fd2706-8baf-433b-82eb-8c7fada847da'), 'bittrex', DIRECTION_BUY, datetime.datetime(2017, 11, 26, 10, 11, 12, tzinfo=datetime.timezone.utc), BTC_USD_PAIR, ORDER_TYPE_MARKET, Decimal('1'), None
def close(self, order: Order, closed_at: datetime.datetime) -> None: order.close(closed_at) self._order_storage.delete(order.order_id) self._order_storage.save_order(order) logger.info('Order "{}" has been successfully CLOSED.'.format( order.order_id))
from influxdb import InfluxDBClient from coinrat.domain.pair import Pair from coinrat.domain.order import Order, ORDER_TYPE_LIMIT, DIRECTION_BUY, DIRECTION_SELL, ORDER_STATUS_OPEN, \ ORDER_STATUS_CLOSED from coinrat_influx_db_storage.order_storage import OrderInnoDbStorage DUMMY_MARKET = 'dummy_market' BTC_USD_PAIR = Pair('USD', 'BTC') DUMMY_ORDER = Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847da'), UUID('99fd2706-8baf-433b-82eb-8c7fada847da'), DUMMY_MARKET, DIRECTION_BUY, datetime.datetime(2017, 11, 26, 10, 11, 12, tzinfo=datetime.timezone.utc), BTC_USD_PAIR, ORDER_TYPE_LIMIT, Decimal('1'), Decimal('8000'), 'aaa-id-from-market' ) @pytest.fixture def influx_database(): influx = InfluxDBClient() influx.create_database('coinrat_test') influx._database = 'coinrat_test' yield influx influx.drop_database('coinrat_test')
import copy import datetime from uuid import UUID from decimal import Decimal from coinrat.domain.pair import Pair from coinrat.domain.order import Order, ORDER_TYPE_LIMIT, OrderMarketInfo, DIRECTION_BUY DUMMY_ORDER_OPEN = Order( UUID('16fd2706-8baf-433b-82eb-8c7fada847db'), UUID('99fd2706-8baf-433b-82eb-8c7fada847da'), 'lorem_ipsum', DIRECTION_BUY, datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc), Pair('USD', 'BTC'), ORDER_TYPE_LIMIT, Decimal('2'), Decimal('9000'), 'bbb-id-from-market', ) def test_open_order(): order = DUMMY_ORDER_OPEN expected = 'BUY-OPEN, ' \ + 'Id: "16fd2706-8baf-433b-82eb-8c7fada847db", ' \ + 'Market: "lorem_ipsum", ' \ + 'Created: "2017-01-02T03:04:05+00:00", ' \ + 'Closed: "None", ' \