ib: add back `src/dst` parsing for fiat pairs
							parent
							
								
									ae444d1bc7
								
							
						
					
					
						commit
						e9dfd28aac
					
				| 
						 | 
					@ -650,12 +650,14 @@ class Client:
 | 
				
			||||||
            exch in {'IDEALPRO'}
 | 
					            exch in {'IDEALPRO'}
 | 
				
			||||||
            or sectype == 'CASH'
 | 
					            or sectype == 'CASH'
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            # if '/' in symbol:
 | 
					            pair: str = symbol
 | 
				
			||||||
            #     currency = ''
 | 
					            if '/' in symbol:
 | 
				
			||||||
            #     symbol, currency = symbol.split('/')
 | 
					                src, dst = symbol.split('/')
 | 
				
			||||||
 | 
					                pair: str = ''.join([src, dst])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            con = Forex(
 | 
					            con = Forex(
 | 
				
			||||||
                pair=''.join((symbol, currency)),
 | 
					                pair=pair,
 | 
				
			||||||
                currency=currency,
 | 
					                currency='',
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            con.bars_kwargs = {'whatToShow': 'MIDPOINT'}
 | 
					            con.bars_kwargs = {'whatToShow': 'MIDPOINT'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@ import time
 | 
				
			||||||
from typing import (
 | 
					from typing import (
 | 
				
			||||||
    Any,
 | 
					    Any,
 | 
				
			||||||
    Callable,
 | 
					    Callable,
 | 
				
			||||||
 | 
					    TYPE_CHECKING,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from async_generator import aclosing
 | 
					from async_generator import aclosing
 | 
				
			||||||
| 
						 | 
					@ -65,6 +66,9 @@ from .api import (
 | 
				
			||||||
from ._util import data_reset_hack
 | 
					from ._util import data_reset_hack
 | 
				
			||||||
from .symbols import get_mkt_info
 | 
					from .symbols import get_mkt_info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if TYPE_CHECKING:
 | 
				
			||||||
 | 
					    from trio._core._run import Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# XXX NOTE: See available types table docs:
 | 
					# XXX NOTE: See available types table docs:
 | 
				
			||||||
# https://interactivebrokers.github.io/tws-api/tick_types.html
 | 
					# https://interactivebrokers.github.io/tws-api/tick_types.html
 | 
				
			||||||
| 
						 | 
					@ -308,7 +312,7 @@ async def wait_on_data_reset(
 | 
				
			||||||
    return False
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_data_resetter_task: trio.Task | None = None
 | 
					_data_resetter_task: Task | None = None
 | 
				
			||||||
_failed_resets: int = 0
 | 
					_failed_resets: int = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -334,7 +338,15 @@ async def get_bars(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    task_status: TaskStatus[trio.CancelScope] = trio.TASK_STATUS_IGNORED,
 | 
					    task_status: TaskStatus[trio.CancelScope] = trio.TASK_STATUS_IGNORED,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
) -> (dict, np.ndarray):
 | 
					) -> tuple[
 | 
				
			||||||
 | 
					    tuple[  # result tuple
 | 
				
			||||||
 | 
					        ibis.objects.BarDataList,
 | 
				
			||||||
 | 
					        np.ndarray,
 | 
				
			||||||
 | 
					        datetime,
 | 
				
			||||||
 | 
					        datetime,
 | 
				
			||||||
 | 
					    ] | None,
 | 
				
			||||||
 | 
					    bool,  # timed out hint
 | 
				
			||||||
 | 
					]:
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    Retrieve historical data from a ``trio``-side task using
 | 
					    Retrieve historical data from a ``trio``-side task using
 | 
				
			||||||
    a ``MethoProxy``.
 | 
					    a ``MethoProxy``.
 | 
				
			||||||
| 
						 | 
					@ -420,7 +432,12 @@ async def get_bars(
 | 
				
			||||||
                if data_cs:
 | 
					                if data_cs:
 | 
				
			||||||
                    data_cs.cancel()
 | 
					                    data_cs.cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                result = (bars, bars_array, first_dt, last_dt)
 | 
					                result = (
 | 
				
			||||||
 | 
					                    bars,  # ib native
 | 
				
			||||||
 | 
					                    bars_array,  # numpy
 | 
				
			||||||
 | 
					                    first_dt,
 | 
				
			||||||
 | 
					                    last_dt,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # signal data reset loop parent task
 | 
					                # signal data reset loop parent task
 | 
				
			||||||
                result_ready.set()
 | 
					                result_ready.set()
 | 
				
			||||||
| 
						 | 
					@ -428,7 +445,7 @@ async def get_bars(
 | 
				
			||||||
                return result
 | 
					                return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            except RequestError as err:
 | 
					            except RequestError as err:
 | 
				
			||||||
                msg = err.message
 | 
					                msg: str = err.message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if 'No market data permissions for' in msg:
 | 
					                if 'No market data permissions for' in msg:
 | 
				
			||||||
                    # TODO: signalling for no permissions searches
 | 
					                    # TODO: signalling for no permissions searches
 | 
				
			||||||
| 
						 | 
					@ -466,21 +483,29 @@ async def get_bars(
 | 
				
			||||||
                    nodatas_count += 1
 | 
					                    nodatas_count += 1
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                elif 'API historical data query cancelled' in err.message:
 | 
					                elif (
 | 
				
			||||||
 | 
					                    'API historical data query cancelled'
 | 
				
			||||||
 | 
					                    in
 | 
				
			||||||
 | 
					                    err.message
 | 
				
			||||||
 | 
					                ):
 | 
				
			||||||
                    log.warning(
 | 
					                    log.warning(
 | 
				
			||||||
                        'Query cancelled by IB (:eyeroll:):\n'
 | 
					                        'Query cancelled by IB (:eyeroll:):\n'
 | 
				
			||||||
                        f'{err.message}'
 | 
					                        f'{err.message}'
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                elif (
 | 
					                elif (
 | 
				
			||||||
                    'Trading TWS session is connected from a different IP'
 | 
					                    'Trading TWS session is connected from a different IP'
 | 
				
			||||||
                        in err.message
 | 
					                    in
 | 
				
			||||||
 | 
					                    err.message
 | 
				
			||||||
                ):
 | 
					                ):
 | 
				
			||||||
                    log.warning("ignoring ip address warning")
 | 
					                    log.warning("ignoring ip address warning")
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # XXX: more or less same as above timeout case
 | 
					                # XXX: more or less same as above timeout case
 | 
				
			||||||
                elif _pacing in msg:
 | 
					                elif (
 | 
				
			||||||
 | 
					                    _pacing in msg
 | 
				
			||||||
 | 
					                ):
 | 
				
			||||||
                    log.warning(
 | 
					                    log.warning(
 | 
				
			||||||
                        'History throttle rate reached!\n'
 | 
					                        'History throttle rate reached!\n'
 | 
				
			||||||
                        'Resetting farms with `ctrl-alt-f` hack\n'
 | 
					                        'Resetting farms with `ctrl-alt-f` hack\n'
 | 
				
			||||||
| 
						 | 
					@ -532,9 +557,10 @@ async def get_bars(
 | 
				
			||||||
                # don't double invoke the reset hack if another
 | 
					                # don't double invoke the reset hack if another
 | 
				
			||||||
                # requester task already has it covered.
 | 
					                # requester task already has it covered.
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                _data_resetter_task = trio.lowlevel.current_task()
 | 
					                _data_resetter_task = trio.lowlevel.current_task()
 | 
				
			||||||
                unset_resetter = True
 | 
					                unset_resetter: bool = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # spawn new data reset task
 | 
					            # spawn new data reset task
 | 
				
			||||||
            data_cs, reset_done = await nurse.start(
 | 
					            data_cs, reset_done = await nurse.start(
 | 
				
			||||||
| 
						 | 
					@ -547,9 +573,16 @@ async def get_bars(
 | 
				
			||||||
            # sync wait on reset to complete
 | 
					            # sync wait on reset to complete
 | 
				
			||||||
            await reset_done.wait()
 | 
					            await reset_done.wait()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _data_resetter_task = None if unset_resetter else _data_resetter_task
 | 
					    _data_resetter_task = (
 | 
				
			||||||
 | 
					        None
 | 
				
			||||||
 | 
					        if unset_resetter
 | 
				
			||||||
 | 
					        else _data_resetter_task
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    assert result
 | 
					    assert result
 | 
				
			||||||
    return result, data_cs is not None
 | 
					    return (
 | 
				
			||||||
 | 
					        result,
 | 
				
			||||||
 | 
					        data_cs is not None,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_quote_streams: dict[str, trio.abc.ReceiveStream] = {}
 | 
					_quote_streams: dict[str, trio.abc.ReceiveStream] = {}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue