コード例 #1
0
from nautilus_trader.model.bar import BarType
from nautilus_trader.model.enums import BarAggregation
from nautilus_trader.model.enums import PriceType
from nautilus_trader.model.identifiers import Symbol
from nautilus_trader.model.identifiers import TraderId
from nautilus_trader.model.identifiers import Venue
from nautilus_trader.model.tick import TradeTick
from nautilus_trader.trading.portfolio import Portfolio
from tests import PACKAGE_ROOT
from tests.test_kit.mocks import ObjectStorer
from tests.test_kit.stubs import TestStubs

TEST_PATH = PACKAGE_ROOT + "/integration_tests/adapters/ccxt/responses/"

BINANCE = Venue("BINANCE")
BTCUSDT = Symbol("BTC/USDT", BINANCE)
ETHUSDT = Symbol("ETH/USDT", BINANCE)

# Monkey patch magic mock
# This allows the stubbing of calls to coroutines
MagicMock.__await__ = lambda x: async_magic().__await__()


# Dummy method for above
async def async_magic():
    return


class CCXTDataClientTests(unittest.TestCase):
    def setUp(self):
        # Fixture Setup
コード例 #2
0
 def ethusd_bitmex_id() -> InstrumentId:
     return InstrumentId(Symbol("ETH/USD"), Venue("BITMEX"))
コード例 #3
0
 def ethusdt_binance_id() -> InstrumentId:
     return InstrumentId(Symbol("ETH/USDT"), Venue("BINANCE"))
コード例 #4
0
 def gbpusd_id() -> InstrumentId:
     return InstrumentId(Symbol("GBP/USD"), Venue("SIM"))
コード例 #5
0
class BidAskMinMaxTests(unittest.TestCase):
    instrument_id = InstrumentId(Symbol("SPY"), Venue("NYSE"))

    def test_instantiate(self):
        # Arrange
        indicator = BidAskMinMax(self.instrument_id, timedelta(minutes=5))

        # Act
        # Assert
        self.assertEqual(None, indicator.bids.min_price)
        self.assertEqual(None, indicator.bids.max_price)
        self.assertEqual(None, indicator.asks.min_price)
        self.assertEqual(None, indicator.asks.max_price)
        self.assertEqual(False, indicator.initialized)

    def test_handle_quote_tick(self):
        # Arrange
        indicator = BidAskMinMax(self.instrument_id, timedelta(minutes=5))

        # Act
        indicator.handle_quote_tick(
            QuoteTick(
                self.instrument_id,
                Price("1.0"),
                Price("2.0"),
                Quantity(1),
                Quantity(1),
                datetime(2020, 1, 1, 0, 0, 0, tzinfo=pytz.utc),
            ))
        # 5 min later (still in the window)
        indicator.handle_quote_tick(
            QuoteTick(
                self.instrument_id,
                Price("0.9"),
                Price("2.1"),
                Quantity(1),
                Quantity(1),
                datetime(2020, 1, 1, 0, 5, 0, tzinfo=pytz.utc),
            ))

        # Assert
        self.assertEqual(Price("0.9"), indicator.bids.min_price)
        self.assertEqual(Price("1.0"), indicator.bids.max_price)
        self.assertEqual(Price("2.1"), indicator.asks.min_price)
        self.assertEqual(Price("2.1"), indicator.asks.max_price)

    def test_reset(self):
        # Arrange
        indicator = BidAskMinMax(self.instrument_id, timedelta(minutes=5))

        indicator.handle_quote_tick(
            QuoteTick(
                self.instrument_id,
                Price("0.9"),
                Price("2.1"),
                Quantity(1),
                Quantity(1),
                datetime(2020, 1, 1, 0, 5, 0, tzinfo=pytz.utc),
            ))

        # Act
        indicator.reset()

        # Assert
        self.assertIsNone(indicator.bids.min_price)
        self.assertIsNone(indicator.asks.min_price)
コード例 #6
0
#  limitations under the License.
# -------------------------------------------------------------------------------------------------

import unittest

from nautilus_trader.execution.base import ExecutionCacheFacade
from nautilus_trader.model.identifiers import AccountId
from nautilus_trader.model.identifiers import ClientOrderId
from nautilus_trader.model.identifiers import PositionId
from nautilus_trader.model.identifiers import Symbol
from nautilus_trader.model.identifiers import Venue
from tests.test_kit.providers import TestInstrumentProvider


SIM = Venue("SIM")
USDJPY_SIM = TestInstrumentProvider.default_fx_ccy(Symbol("USD/JPY", SIM))
AUDUSD_SIM = TestInstrumentProvider.default_fx_ccy(Symbol("AUD/USD", SIM))


class ExecutionCacheFacadeTests(unittest.TestCase):

    def setUp(self):
        # Fixture Setup
        self.facade = ExecutionCacheFacade()

    def test_account_when_not_implemented_raises_exception(self):
        self.assertRaises(NotImplementedError, self.facade.account, AccountId("SIM", "000"))

    def test_account_for_venue_when_not_implemented_raises_exception(self):
        self.assertRaises(NotImplementedError, self.facade.account_for_venue, SIM)
コード例 #7
0
from nautilus_trader.model.objects import Price
from nautilus_trader.model.objects import Quantity
from nautilus_trader.model.position import Position
from nautilus_trader.model.tick import QuoteTick
from nautilus_trader.trading.account import Account
from nautilus_trader.trading.portfolio import Portfolio
from nautilus_trader.trading.portfolio import PortfolioFacade
from tests.test_kit.providers import TestInstrumentProvider
from tests.test_kit.stubs import TestStubs
from tests.test_kit.stubs import UNIX_EPOCH

SIM = Venue("SIM")
BINANCE = Venue("BINANCE")
BITMEX = Venue("BITMEX")

AUDUSD_SIM = TestInstrumentProvider.default_fx_ccy(Symbol(
    "AUD/USD", Venue("SIM")),
                                                   leverage=Decimal("50"))
GBPUSD_SIM = TestInstrumentProvider.default_fx_ccy(Symbol(
    "GBP/USD", Venue("SIM")),
                                                   leverage=Decimal("50"))
USDJPY_SIM = TestInstrumentProvider.default_fx_ccy(Symbol(
    "USD/JPY", Venue("SIM")),
                                                   leverage=Decimal("50"))
BTCUSDT_BINANCE = TestInstrumentProvider.btcusdt_binance()
BTCUSD_BITMEX = TestInstrumentProvider.xbtusd_bitmex(leverage=Decimal("10"))
ETHUSD_BITMEX = TestInstrumentProvider.ethusd_bitmex(leverage=Decimal("10"))


class PortfolioFacadeTests(unittest.TestCase):
    def test_account_raises_not_implemented_error(self):
        # Arrange
            "account_id":
            "BITMEX_ACCOUNT_ID",  # value is the environment variable key
            "api_key":
            "BITMEX_API_KEY",  # value is the environment variable key
            "api_secret":
            "BITMEX_API_SECRET",  # value is the environment variable key
        },
    },
}

# Instantiate your strategies to pass into the trading node. You could add
# custom options into the configuration file or even use another configuration
# file.

instrument1 = InstrumentId(
    symbol=Symbol("ETH/USDT"),
    venue=Venue("BINANCE"),
)

strategy1 = EMACross(
    instrument_id=instrument1,
    bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.LAST),
    trade_size=Decimal("0.02"),
    fast_ema_period=10,
    slow_ema_period=20,
    order_id_tag="003",
)

# ------------------------------------------------------------------------------

instrument2 = InstrumentId(
コード例 #9
0
ファイル: providers.py プロジェクト: FGU1/nautilus_trader
    def default_fx_ccy(symbol: str, venue: Venue = None) -> CurrencySpot:
        """
        Return a default FX currency pair instrument from the given instrument_id.

        Parameters
        ----------
        symbol : str
            The currency pair symbol.
        venue : Venue
            The currency pair venue.

        Returns
        -------
        CurrencySpot

        Raises
        ------
        ValueError
            If the instrument_id.instrument_id length is not in range [6, 7].

        """
        if venue is None:
            venue = Venue("SIM")
        PyCondition.valid_string(symbol, "symbol")
        PyCondition.in_range_int(len(symbol), 6, 7, "len(symbol)")

        instrument_id = InstrumentId(
            symbol=Symbol(symbol),
            venue=venue,
        )

        base_currency = symbol[:3]
        quote_currency = symbol[-3:]

        # Check tick precision of quote currency
        if quote_currency == "JPY":
            price_precision = 3
        else:
            price_precision = 5

        return CurrencySpot(
            instrument_id=instrument_id,
            base_currency=Currency.from_str(base_currency),
            quote_currency=Currency.from_str(quote_currency),
            price_precision=price_precision,
            size_precision=0,
            price_increment=Price(1 / 10**price_precision, price_precision),
            size_increment=Quantity.from_int(1),
            lot_size=Quantity.from_str("1000"),
            max_quantity=Quantity.from_str("1e7"),
            min_quantity=Quantity.from_str("1000"),
            max_price=None,
            min_price=None,
            max_notional=Money(50000000.00, USD),
            min_notional=Money(1000.00, USD),
            margin_init=Decimal("0.03"),
            margin_maint=Decimal("0.03"),
            maker_fee=Decimal("0.00002"),
            taker_fee=Decimal("0.00002"),
            timestamp_origin_ns=0,
            timestamp_ns=0,
        )
コード例 #10
0
# BarSpecification options
# ------------------------
# price types include BID, ASK, MID, LAST
# Current aggregations TICK, SECOND, MINUTE, HOUR, DAY, VOLUME, VALUE
# These can be combined in any way, for example;
tick_bars = BarSpecification(100, BarAggregation.TICK, PriceType.LAST)
time_bars = BarSpecification(1, BarAggregation.MINUTE, PriceType.LAST)
volu_bars = BarSpecification(100, BarAggregation.VOLUME, PriceType.MID)
valu_bars = BarSpecification(1_000_000, BarAggregation.VALUE, PriceType.MID)

# Instantiate your strategies to pass into the trading node. You could add
# custom options into the configuration file or even use another configuration
# file.
strategy = EMACross(
    symbol=Symbol("ETH/USDT", Venue("BINANCE")),
    bar_spec=time_bars,
    fast_ema_period=10,
    slow_ema_period=20,
    trade_size=Decimal("0.05"),
    order_id_tag="001",
)

# Instantiate the node passing a list of strategies and configuration
node = TradingNode(strategies=[strategy], config=config)

# Stop and dispose of the node with SIGINT/CTRL+C
if __name__ == "__main__":
    try:
        node.start()
    finally:
コード例 #11
0
            "BITMEX_ACCOUNT_ID",  # value is the environment variable key
            "api_key":
            "BITMEX_API_KEY",  # value is the environment variable key
            "api_secret":
            "BITMEX_API_SECRET",  # value is the environment variable key
            "sandbox_mode": False,  # If clients use the testnet
        },
    },
}

# Instantiate your strategies to pass into the trading node. You could add
# custom options into the configuration file or even use another configuration
# file.

instrument_id = InstrumentId(
    symbol=Symbol("BTC/USD"),
    venue=Venue("BITMEX"),
)

strategy = EMACross(
    instrument_id=instrument_id,
    bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.LAST),
    fast_ema_period=10,
    slow_ema_period=20,
    trade_size=Decimal("10"),
    order_id_tag="002",
)

# Instantiate the node passing a list of strategies and configuration
node = TradingNode(strategies=[strategy], config=config)
            "exec_client": True,  # If a exec client should be created
            "account_id":
            "BITMEX_ACCOUNT_ID",  # value is the environment variable key
            "api_key":
            "BITMEX_API_KEY",  # value is the environment variable key
            "api_secret":
            "BITMEX_API_SECRET",  # value is the environment variable key
        },
    },
}

# Instantiate your strategies to pass into the trading node. You could add
# custom options into the configuration file or even use another configuration
# file.
strategy1 = EMACross(
    symbol=Symbol("ETH/USDT", Venue("BINANCE")),
    bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.LAST),
    trade_size=Decimal("0.02"),
    fast_ema_period=10,
    slow_ema_period=20,
    order_id_tag="003",
)

strategy2 = EMACrossStopEntryTrail(
    symbol=Symbol("BTC/USD", Venue("BITMEX")),
    bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.LAST),
    trade_size=Decimal("100"),
    fast_ema_period=10,
    slow_ema_period=20,
    atr_period=20,
    trail_atr_multiple=2.0,
コード例 #13
0
            "BINANCE_ACCOUNT_ID",  # value is the environment variable key
            "api_key":
            "BINANCE_API_KEY",  # value is the environment variable key
            "api_secret":
            "BINANCE_API_SECRET",  # value is the environment variable key
            "sandbox_mode": False,  # If clients use the testnet
        },
    },
}

# Instantiate your strategies to pass into the trading node. You could add
# custom options into the configuration file or even use another configuration
# file.

instrument_id = InstrumentId(
    symbol=Symbol("ETH/USDT"),
    venue=Venue("BINANCE"),
)

strategy = EMACross(
    instrument_id=instrument_id,
    bar_spec=BarSpecification(1, BarAggregation.MINUTE, PriceType.LAST),
    fast_ema_period=10,
    slow_ema_period=20,
    trade_size=Decimal("0.05"),
    order_id_tag="001",
)

# Instantiate the node passing a list of strategies and configuration
node = TradingNode(strategies=[strategy], config=config)
コード例 #14
0
class TestBarType:
    def test_bar_type_equality(self):
        # Arrange
        instrument_id1 = InstrumentId(Symbol("AUD/USD"), Venue("SIM"))
        instrument_id2 = InstrumentId(Symbol("GBP/USD"), Venue("SIM"))
        bar_spec = BarSpecification(1, BarAggregation.MINUTE, PriceType.BID)
        bar_type1 = BarType(instrument_id1, bar_spec)
        bar_type2 = BarType(instrument_id1, bar_spec)
        bar_type3 = BarType(instrument_id2, bar_spec)

        # Act
        # Assert
        assert bar_type1 == bar_type1
        assert bar_type1 == bar_type2
        assert bar_type1 != bar_type3

    def test_bar_type_to_serializable_string(self):
        # Arrange
        instrument_id = InstrumentId(Symbol("AUD/USD"), Venue("IDEALPRO"))
        bar_spec = BarSpecification(1, BarAggregation.MINUTE, PriceType.BID)
        bar_type = BarType(instrument_id, bar_spec)

        # Act
        result = bar_type.to_serializable_str()

        # Assert
        assert "AUD/USD.IDEALPRO-1-MINUTE-BID" == result

    def test_bar_type_hash_str_and_repr(self):
        # Arrange
        instrument_id = InstrumentId(Symbol("AUD/USD"), Venue("SIM"))
        bar_spec = BarSpecification(1, BarAggregation.MINUTE, PriceType.BID)
        bar_type = BarType(instrument_id, bar_spec)

        # Act
        # Assert
        assert isinstance(hash(bar_type), int)
        assert "AUD/USD.SIM-1-MINUTE-BID" == str(bar_type)
        assert "BarType(AUD/USD.SIM-1-MINUTE-BID, internal_aggregation=True)" == repr(
            bar_type)

    @pytest.mark.parametrize(
        "value",
        ["", "AUD/USD", "AUD/USD.IDEALPRO-1-MILLISECOND-BID"],
    )
    def test_from_str_given_various_invalid_strings_raises_value_error(
            self, value):
        # Arrange
        # Act
        # Assert
        with pytest.raises(ValueError):
            BarType.from_serializable_str(value)

    @pytest.mark.parametrize(
        "value, expected",
        [
            [
                "AUD/USD.IDEALPRO-1-MINUTE-BID",
                BarType(
                    InstrumentId(Symbol("AUD/USD"), Venue("IDEALPRO")),
                    BarSpecification(1, BarAggregation.MINUTE, PriceType.BID))
            ],  # noqa
            [
                "GBP/USD.SIM-1000-TICK-MID",
                BarType(
                    InstrumentId(Symbol("GBP/USD"), Venue("SIM")),
                    BarSpecification(1000, BarAggregation.TICK, PriceType.MID))
            ],  # noqa
            [
                "AAPL.NYSE-1-HOUR-MID",
                BarType(
                    InstrumentId(Symbol("AAPL"), Venue("NYSE")),
                    BarSpecification(1, BarAggregation.HOUR, PriceType.MID))
            ],  # noqa
            [
                "BTC/USDT.BINANCE-100-TICK-LAST",
                BarType(
                    InstrumentId(Symbol("BTC/USDT"), Venue("BINANCE")),
                    BarSpecification(100, BarAggregation.TICK, PriceType.LAST))
            ]
        ],  # noqa
    )
    def test_from_str_given_various_valid_string_returns_expected_specification(
            self, value, expected):
        # Arrange
        # Act
        bar_type = BarType.from_serializable_str(value,
                                                 internal_aggregation=True)

        # Assert
        assert bar_type == expected
コード例 #15
0
ファイル: stubs.py プロジェクト: thorjeus/nautilus_trader
 def symbol_gbpusd_fxcm() -> Symbol:
     return Symbol("GBP/USD", Venue("SIM"))
コード例 #16
0
def instrument_id():
    return InstrumentId(symbol=Symbol("Test"), venue=BETFAIR_VENUE)
コード例 #17
0
ファイル: stubs.py プロジェクト: thorjeus/nautilus_trader
 def symbol_usdjpy_fxcm() -> Symbol:
     return Symbol("USD/JPY", Venue("SIM"))
コード例 #18
0
#  See the License for the specific language governing permissions and
#  limitations under the License.
# -------------------------------------------------------------------------------------------------

import unittest

from nautilus_trader.core.message import Message
from nautilus_trader.core.message import MessageType
from nautilus_trader.core.uuid import uuid4
from nautilus_trader.model.commands import SubmitOrder
from nautilus_trader.model.identifiers import InstrumentId
from nautilus_trader.model.identifiers import Symbol
from nautilus_trader.model.identifiers import Venue
from tests.test_kit.performance import PerformanceHarness

AUDUSD = InstrumentId(Symbol("AUDUSD"), Venue("IDEALPRO"))
MESSAGE = Message(MessageType.COMMAND, uuid4(), 0)


class Experiments:
    @staticmethod
    def built_in_arithmetic():
        x = 1 + 1
        return x

    @staticmethod
    def class_name():
        x = "123".__class__.__name__
        return x

    @staticmethod
コード例 #19
0
# BarSpecification options
# ------------------------
# price types include BID, ASK, MID, LAST
# Current aggregations TICK, SECOND, MINUTE, HOUR, DAY, VOLUME, VALUE
# These can be combined in any way, for example;
tick_bars = BarSpecification(100, BarAggregation.TICK, PriceType.LAST)
time_bars = BarSpecification(1, BarAggregation.MINUTE, PriceType.LAST)
volu_bars = BarSpecification(100, BarAggregation.VOLUME, PriceType.MID)
valu_bars = BarSpecification(1_000_000, BarAggregation.VALUE, PriceType.MID)

# Instantiate your strategies to pass into the trading node. You could add
# custom options into the configuration file or even use another configuration
# file.
strategy = EMACross(
    symbol=Symbol("BTC/USD", Venue("BITMEX")),
    bar_spec=time_bars,
    fast_ema_period=10,
    slow_ema_period=20,
    trade_size=Decimal("10"),
)

# Instantiate the node passing a list of strategies and configuration
node = TradingNode(strategies=[strategy], config=config)

# Stop and dispose of the node with SIGINT/CTRL+C
if __name__ == "__main__":
    try:
        node.start()
    finally:
        node.dispose()
コード例 #20
0
ファイル: stubs.py プロジェクト: thorjeus/nautilus_trader
 def symbol_btcusd_bitmex() -> Symbol:
     return Symbol("BTC/USD", Venue("BITMEX"))
コード例 #21
0
 def usdjpy_id() -> InstrumentId:
     return InstrumentId(Symbol("USD/JPY"), Venue("SIM"))
コード例 #22
0
ファイル: stubs.py プロジェクト: thorjeus/nautilus_trader
 def symbol_ethusd_bitmex() -> Symbol:
     return Symbol("ETH/USD", Venue("BITMEX"))
コード例 #23
0
from nautilus_trader.model.enums import OMSType
from nautilus_trader.model.enums import PriceType
from nautilus_trader.model.identifiers import Symbol
from nautilus_trader.model.identifiers import Venue
from nautilus_trader.model.objects import Money
from tests.test_kit.providers import TestDataProvider

if __name__ == "__main__":
    # Setup trading instruments
    # Requires an internet connection for the instrument loader
    # Alternatively use the TestInstrumentProvider in the test kit
    print("Loading instruments...")
    instruments = CCXTInstrumentProvider(client=ccxt.binance(), load_all=True)

    BINANCE = Venue("BINANCE")
    ETHUSDT_BINANCE = instruments.get(Symbol("ETH/USDT", BINANCE))

    # Setup data container
    data = BacktestDataContainer()
    data.add_instrument(ETHUSDT_BINANCE)
    data.add_trade_ticks(ETHUSDT_BINANCE.symbol,
                         TestDataProvider.ethusdt_trades())

    # Instantiate your strategy
    strategy = EMACross(
        symbol=ETHUSDT_BINANCE.symbol,
        bar_spec=BarSpecification(250, BarAggregation.TICK, PriceType.LAST),
        fast_ema_period=10,
        slow_ema_period=20,
        trade_size=Decimal(100),
        order_id_tag="001",
コード例 #24
0
ファイル: stubs.py プロジェクト: thorjeus/nautilus_trader
 def symbol_btcusdt_binance() -> Symbol:
     return Symbol("BTC/USDT", Venue("BINANCE"))
コード例 #25
0
 def btcusd_bitmex_id() -> InstrumentId:
     return InstrumentId(Symbol("BTC/USD"), Venue("BITMEX"))
コード例 #26
0
ファイル: stubs.py プロジェクト: thorjeus/nautilus_trader
 def symbol_ethusdt_binance() -> Symbol:
     return Symbol("ETH/USDT", Venue("BINANCE"))
コード例 #27
0
 def btcusdt_binance_id() -> InstrumentId:
     return InstrumentId(Symbol("BTC/USDT"), Venue("BINANCE"))
コード例 #28
0
ファイル: stubs.py プロジェクト: thorjeus/nautilus_trader
 def symbol_audusd_fxcm() -> Symbol:
     return Symbol("AUD/USD", Venue("SIM"))
コード例 #29
0
 def audusd_id() -> InstrumentId:
     return InstrumentId(Symbol("AUD/USD"), Venue("SIM"))
コード例 #30
0
class BarTypeTests(unittest.TestCase):
    def test_bar_type_equality(self):
        # Arrange
        symbol1 = Symbol("AUD/USD", Venue("SIM"))
        symbol2 = Symbol("GBP/USD", Venue("SIM"))
        bar_spec = BarSpecification(1, BarAggregation.MINUTE, PriceType.BID)
        bar_type1 = BarType(symbol1, bar_spec)
        bar_type2 = BarType(symbol1, bar_spec)
        bar_type3 = BarType(symbol2, bar_spec)

        # Act
        # Assert
        self.assertTrue(bar_type1 == bar_type1)
        self.assertTrue(bar_type1 == bar_type2)
        self.assertTrue(bar_type1 != bar_type3)

    def test_bar_type_str_and_repr(self):
        # Arrange
        symbol = Symbol("AUD/USD", Venue("SIM"))
        bar_spec = BarSpecification(1, BarAggregation.MINUTE, PriceType.BID)
        bar_type = BarType(symbol, bar_spec)

        # Act
        # Assert
        self.assertEqual("AUD/USD.SIM-1-MINUTE-BID", str(bar_type))
        self.assertEqual(
            "BarType(AUD/USD.SIM-1-MINUTE-BID, internal_aggregation=True)",
            repr(bar_type))

    @parameterized.expand([
        [""],
        ["AUD/USD"],
        ["AUD/USD.IDEALPRO-1-MILLISECOND-BID"],
    ])
    def test_from_str_given_various_invalid_strings_raises_value_error(
            self, value):
        # Arrange
        # Act
        # Assert
        self.assertRaises(ValueError, BarType.from_str, value)

    @parameterized.expand([
        [
            "AUD/USD.IDEALPRO-1-MINUTE-BID",
            BarType(Symbol("AUD/USD", Venue("IDEALPRO")),
                    BarSpecification(1, BarAggregation.MINUTE, PriceType.BID))
        ],
        [
            "GBP/USD.SIM-1000-TICK-MID",
            BarType(Symbol("GBP/USD", Venue("SIM")),
                    BarSpecification(1000, BarAggregation.TICK, PriceType.MID))
        ],
        [
            "AAPL.NYSE-1-HOUR-MID",
            BarType(Symbol("AAPL", Venue("NYSE")),
                    BarSpecification(1, BarAggregation.HOUR, PriceType.MID))
        ],
        [
            "BTC/USDT.BINANCE-100-TICK-LAST",
            BarType(Symbol("BTC/USDT", Venue("BINANCE")),
                    BarSpecification(100, BarAggregation.TICK, PriceType.LAST))
        ],
    ])
    def test_from_str_given_various_valid_string_returns_expected_specification(
            self, value, expected):
        # Arrange
        # Act
        bar_type = BarType.from_str(value, internal_aggregation=True)

        # Assert
        self.assertEqual(bar_type, expected)