def update_prices(self, prices: List[dict]): instrument_service_prices = defaultdict(lambda: defaultdict(list)) for price in prices: instrument_service_prices[price['instrument']][ price['service']].append(price) signals = [] # type: List[dict] spreads = [] # type: List[dict] for instrument, service_prices in instrument_service_prices.items(): service_pairs = sorted(itertools.permutations( service_prices.keys(), 2), key=str) for b, a in service_pairs: bid_data, ask_data = service_prices[b][-1], service_prices[a][ -1] signaler = self.get_signaler(instrument, b, a) d = signaler.judge(bid_data=bid_data, ask_data=ask_data) if d: spreads.append(d) # minus spread if d['signaled']: d['signaler'] = signaler d['bg'] = None d['signaled_time'] = d['time'].strftime( '%Y-%m-%d %H:%M:%S.%f%Z') d['sp'] = '{:.2f}'.format(d['sp']) signals.append(d) GlobalSignal().update_signals.emit(signals) GlobalSignal().update_spreads.emit(spreads)
def update_prices(): services = [ 'click', 'gaitame', 'lion', 'pfx', 'nano', 'sbi', 'try', 'yjfx', 'noaccount' ] instruments = ('USD/JPY', 'EUR/JPY', 'GBP/JPY', 'AUD/JPY') prices = [] accounts = [] for service in services: positions = {} for i, instrument in enumerate(instruments): bid = 101 + i + random.random() * 0.8 / 100 ask = 100 + i + random.random() * 0.2 / 100 prices.append( dict(time=timeutil.jst_now(), service=service, instrument=instrument, bid=bid, ask=ask)) if services.index(service) < len(services) / 2: positions[instrument] = random.randint(0, 3) * 1000 else: positions[instrument] = random.randint(0, 3) * -1000 if service != 'noaccount': accounts += [new_account(service, positions=positions)] GlobalSignal().update_prices.emit(prices) GlobalSignal().update_accounts.emit(accounts)
def __init__(self, *, spread_log: str = None, signal_log: str = None): super().__init__() self.spread_log = spread_log self.signal_log = signal_log if spread_log: GlobalSignal().update_spreads.connect(self.update_spreads) if signal_log: GlobalSignal().update_signals.connect(self.update_signals)
def __init__(self, name: str): labels = ['E', 'service', 'time', 'equity', 'pl', 'margin', 'amount'] super().__init__(labels=labels, name=name) self.instrument = '' self.cellClicked.connect(self.cell_clicked) GlobalSignal().update_accounts.connect(self.update_accounts) GlobalSignal().update_prices.connect(self.update_prices) self.services = set()
def __init__(self, *, name: str): labels = ['signaled_time', 'instrument', 'bidder', 'asker', 'sp'] super().__init__(labels=labels, name=name) self.signalers = {} self.signals = [] GlobalSignal().update_prices.connect(self.update_prices) GlobalSignal().update_signals.connect(self.update_signals) GlobalSignal().update_filters.connect(self.refresh_log)
def __init__(self, *args, name: str, **kwargs): labels = ('service', 'sell', 'buy', 'disabled') super().__init__(labels=labels, name=name) self.setContentsMargins(0, 0, 0, 0) self.verticalHeader().hide() self.instrument = '' font = self.horizontalHeader().font() # font.setPointSize(5) self.horizontalHeader().setFont(font) GlobalSignal().update_services.connect(self.update_services) GlobalSignal().update_filters.connect(self.update_filters) GlobalSignal().update_disabled_services.connect(self.update_disabled_services) self.cellClicked.connect(self.cell_clicked)
def __init__(self, bind_address: Tuple[str, int]): super().__init__(name='appmaster', bind_address=bind_address) config = Config() self.window = AppWindow(name='appwindow') GlobalSignal().load_config.emit() GlobalSignal().call_lazy() self.window.show() self.pools = {} # type: Dict[str, Pool] self.elapsed_list = [] self.request_elapsed_list = [] self.account_task = gevent.spawn(self.get_accounts)
def __init__(self, *, name: str): super().__init__(name=name) config = self.config Config().instruments.clear() Config().services.clear() self.setContentsMargins(0, 0, 0, 0) w = QWidget() w.setContentsMargins(0, 0, 0, 0) splitter = Splitter(Qt.Vertical, name=name + '.splitter') splitter.setContentsMargins(0, 0, 0, 0) self.setCentralWidget(splitter) # filter view filter_view = FilterView(name=name + '.filter_view') splitter.addWidget(filter_view) # sound player player = SoundPlayer(name=name + '.sound_player') splitter.addWidget(player) # signal log view signal_log_view = SignalLogView(name=name + '.signal_log_view') # lo.addWidget(signal_log) splitter.addWidget(signal_log_view) # signal slot GlobalSignal().update_prices.connect(self.update_prices) # style sheet self.setStyleSheet('QSplitter::handle{background: white;}') return
def update_signals(self, signals: List[dict]): filters = Config().filters selected = Config().selected_instruments disabled = Config().disabled_services for signal in signals: b, a = signal['bidder'], signal['asker'] if signal['instrument'] not in selected or b in disabled or a in disabled: pass else: bidder_amount = get_amount(signal['bidder'], signal['instrument']) asker_amount = get_amount(signal['asker'], signal['instrument']) if bidder_amount > 0 and asker_amount < 0: signal['bg'] = QBrush(Qt.green) GlobalSignal().play_sound.emit('signal_close') else: GlobalSignal().play_sound.emit('signal_open') self.signals.append(signal) self.refresh_log()
def get_prices(self): now = timeutil.jst_now() def extend_prices(_pool: Pool): with _pool.connection() as client: l = client.get_prices() or [] for x in l: x['time'] = now prices.extend(l) prices = [] spawns = { key: gevent.spawn(lambda _pool: extend_prices(_pool), pool) for key, pool in random.sample(list(self.pools.items()), len(self.pools)) } gevent.joinall(list(spawns.values()), timeout=1) is_timeout = False for key, spawn in spawns.items(): if not spawn.successful(): is_timeout = True try: del self.pools[key] except KeyError: pass try: del self.registered[key[0]] except KeyError: pass elapsed = timeutil.jst_now() - now self.request_elapsed_list.append(elapsed) if prices: GlobalSignal().update_prices.emit(prices) elapsed = timeutil.jst_now() - now self.elapsed_list.append(elapsed) N = 10 if elapsed > timedelta() and len(self.elapsed_list) >= N: request_total = sum( map(lambda x: x.total_seconds(), self.request_elapsed_list)) total = sum(map(lambda x: x.total_seconds(), self.elapsed_list)) self.logger.info( '# elapsed:{:.3f}, request:{:.3f}({:.2f}%), 1loop: {:.3f}, request:{:.3f}' .format(total, request_total, request_total / total * 100, total / N, request_total / N)) self.elapsed_list = [] self.request_elapsed_list = [] if is_timeout: self.logger.warn('#timeout sleep(3)') gevent.sleep(3) else: gevent.sleep( max((timedelta(seconds=Config()['interval']) - elapsed).total_seconds(), 0.05))
def __init__(self, *, name: str): labels = ['bidder', 'bid', 'sp', 'ask', 'asker'] super().__init__(labels=labels, name=name) self.setContentsMargins(0, 0, 0, 0) self.instrument = '' self.setHorizontalHeaderLabels([''] * len(self.labels)) font = self.horizontalHeader().font() font.setPointSize(1) self.horizontalHeader().setFont(font) self.verticalHeader().hide() GlobalSignal().update_prices.connect(self.update_prices)
def __init__(self, name: str): super().__init__(name=name) add_tab = QPushButton('+') add_tab.setMaximumWidth(24) self.setExpanding(False) self.addTab('') self.setTabButton(0, 1, add_tab) self.setTabsClosable(True) self.setMovable(True) add_tab.clicked.connect(self.add_tab) self.tabCloseRequested.connect(self.close_tab) GlobalSignal().update_spreads.connect(self.update_spreads)
def get_accounts(self): import time next_refresh = time.time() + random.random() * 3600 while True: # GlobalSignal().update_accounts.emit([]) # gevent.sleep(10) # continue try: accounts = [] do_refresh = self.do_refresh self.do_refresh = False def extend_accounts(_pool: Pool): with _pool.connection() as client: l = client.get_accounts() or [] if do_refresh: client.refresh() accounts.extend(l) spawns = { key: gevent.spawn(lambda _pool: extend_accounts(_pool), pool) for key, pool in random.sample(list(self.pools.items()), len(self.pools)) } gevent.joinall(list(spawns.values()), timeout=1) is_timeout = False for key, spawn in spawns.items(): if not spawn.successful(): is_timeout = True try: del self.pools[key] except KeyError: pass try: del self.registered[key[0]] except KeyError: pass if accounts: GlobalSignal().update_accounts.emit(accounts) except Exception as e: self.logger.exception(str(e)) gevent.sleep(1)
def __init__(self, *, name: str): super().__init__(name=name) self.sounds = self.config.setdefault( 'sounds', { 'signal_open': { 'file': './signal_open.wav', 'loop': 1, }, 'signal_close': { 'file': './signal_close.wav', 'loop': 3, }, }) self.q_sounds = {} test_button = QPushButton('sound test') test_button.setContentsMargins(0, 0, 0, 0) mute = QCheckBox('Mute') mute.setChecked(self.config.setdefault('mute', False)) check = QCheckBox('CloseOnly') check.setChecked(self.config.setdefault('close_only', False)) def check_clicked_slot(key): @pyqtSlot(bool) def check_clicked(b): self.config[key] = b return check_clicked test_button.clicked.connect( lambda: self.play('signal_open') if not self.config['close_only'] else self.play('signal_close')) mute.clicked.connect(check_clicked_slot('mute')) check.clicked.connect(check_clicked_slot('close_only')) lo = QHBoxLayout() lo.setContentsMargins(0, 0, 0, 0) lo.addStretch() lo.addWidget(test_button) lo.addWidget(mute) lo.addWidget(check) self.setLayout(lo) GlobalSignal().play_sound.connect(self.play)
def __init__(self, name, nodes): super().__init__(name, bind_address=nodes[name], nodes=nodes) self.config = Config() self.window = AppWindow(name='appwindow') GlobalSignal().load_config.emit() GlobalSignal().call_lazy() self.window.show() self.pools = {} # type: Dict[str, Pool] self.elapsed_list = [] self.request_elapsed_list = [] self.do_reload = False self.do_refresh = False def on_reload(): self.do_reload = True def on_refresh(): def call(): self.info('refresh start') for name, address in self._nodes.items(): if name == self.name: continue try: self.info('refresh {}{}'.format(name, address)) self.rpc(address).refresh() except Exception as e: self.exception('refresh {}{} {}'.format( name, address, str(e))) threading.Thread(target=call, daemon=True).start() self.do_refresh = True GlobalSignal().reload.connect(on_reload) GlobalSignal().refresh.connect(on_refresh) import time self._last_tick = time.time() self._accounts = {} self._setsock = False self.run_notify_nodes = lambda: None def write_csv(file_name: str, flush_interval: float): now = datetime.now().date() with open(file_name + now.strftime('_%Y%m%d'), 'a') as f: w = csv.writer(f) flush_at = time.time() while True: d = yield if d: keys = [ 'time', 'instrument', 'bidder', 'asker', 'bid', 'ask', 'sp' ] d = dict(**d) instrument = d['instrument'] d['time'] = d['time'].astimezone(timeutil.TOKYO) d['bid'] = get_float_format(instrument).format( d['bid']) d['ask'] = get_float_format(instrument).format( d['ask']) if isinstance(d['sp'], float): d['sp'] = '{:.2f}'.format(d['sp']) values = [d[k] for k in keys] w.writerow(values) if time.time() - flush_at >= flush_interval: f.flush() flush_at = time.time() self.csv_writer = write_csv('./spread_log.csv', 10.0) self.csv_writer.send(None) self.last_spread_at = timeutil.jst_now()
def closeEvent(self, e: QCloseEvent): GlobalSignal().dump_config.emit() config = Config() if config['auto_save']: yamlutil.save_yaml(dict(config), config['config_file']) e.accept()
def handle_udp(self, data, address: Tuple[str, int]): if not self._setsock: modify_buf_size(self._udp_server._socket, 0x10000, 1024**2 * 4) self._setsock = True assert isinstance(data, dict), '{}'.format(data) self.handle(**data) now = datetime.utcnow().replace(tzinfo=pytz.utc) minus_spreads = [] for (bidder, asker), instrument_spreads in self.spreads.items(): for instrument, spreads in instrument_spreads.items(): if spreads[-1].time > self.last_spread_at and get_pip_scale( spreads[-1].instrument) * (-spreads[-1].sp) < -0.25: minus_spreads.append(spreads[-1]) self.last_spread_at = now for s in minus_spreads: d = dict(bidder=s.pair[0], asker=s.pair[1], instrument=s.instrument, time=s.time, bid=s.bid, ask=s.ask, sp=get_pip_scale(s.instrument) * (-s.sp)) self.csv_writer.send(d) import time if time.time() - self._last_tick <= self.config['interval']: return self._last_tick = time.time() if not minus_spreads: self.csv_writer.send(None) if 'accounts' in data: accounts = [ account.to_dict() for account in self.accounts.values() ] for account in accounts: account['service'] = account['name'] account['pl'] = account['profit_loss'] account[ 'available'] = account['equity'] - account['used_margin'] account['margin_ratio'] = ( account['equity'] / account['used_margin'] ) * 100 if account['used_margin'] > 0 else 0 for account in accounts: self._accounts[account['name']] = account GlobalSignal().update_accounts.emit(list(self._accounts.values())) if 'prices' in data: _prices = [] for service, instrument_prices in self.prices.items(): for instrument, prices in instrument_prices.items(): if len(prices) > 0: _prices.append(prices[-1].to_dict()) [price.update(service=price['name']) for price in _prices] _prices = list( filter(lambda x: (now - x['time']).total_seconds() < 5, _prices)) # # print('#prices') GlobalSignal().update_prices.emit(_prices)
def __init__(self, *, name: str): super().__init__(name=name) config = self.config Config().instruments.clear() Config().services.clear() self.setContentsMargins(0, 0, 0, 0) w = QWidget() w.setContentsMargins(0, 0, 0, 0) splitter = Splitter(Qt.Vertical, name=name + '.splitter') splitter.setContentsMargins(0, 0, 0, 0) self.setCentralWidget(splitter) # filter view for i in range(4): filter_view = FilterView(name=name + '.filter_view_{}'.format(i)) splitter.addWidget(filter_view) # accounts view accounts_view = AccountsView(name=name + '.accounts_view') splitter.addWidget(accounts_view) w = QWidget() splitter.addWidget(w) # spread intrval def update_interval(value: float): Config()['interval'] = value spread_interval = DoubleSpinBox(name='spread_interval', value=0.5, min=0.01, max=3.0, decimals=2, single_step=0.01) spread_interval.valueChanged.connect(update_interval) # bank view bank = DoubleSpinBox(name='tobank', value=0.0, min=-10000000, max=10000000, decimals=0, single_step=1000) bank.valueChanged.connect(accounts_view.update_bank) # refresh button refresh_button = QPushButton('Refresh') refresh_button.clicked.connect(lambda: GlobalSignal().refresh.emit()) lo = QHBoxLayout() lo.setContentsMargins(0, 0, 0, 0) lo.addWidget(refresh_button) lo.addWidget(bank) lo.addWidget(spread_interval) w.setLayout(lo) # sound player player = SoundPlayer(name=name + '.sound_player') # splitter.addWidget(player) lo.addWidget(player) # signal log view signal_log_view = SignalLogView(name=name + '.signal_log_view') # lo.addWidget(signal_log) splitter.addWidget(signal_log_view) # signal slot GlobalSignal().update_prices.connect(self.update_prices) # style sheet self.setStyleSheet('QSplitter::handle{background: white;}') return
def __init__(self, service: str = '', *, name: str): super().__init__(name=name) self.addItem(service) self.setCurrentText(service) GlobalSignal().update_services.connect(self.update_services)
def __init__(self): if not self._initialized: super().__init__() self._dict = dict() self._signals = GlobalSignal() self._initialized = True
def __init__(self, *args, name, **kwargs): super().__init__(*args, **kwargs) self.name = name if name: GlobalSignal().dump_config.connect(self.dump_config) GlobalSignal().load_config.connect(self.load_config)
def __init__(self, instrument: str = '', *, name: str): super().__init__(name=name) self.addItem(instrument) self.setCurrentText(instrument) self.update_instruments(Config().instruments) GlobalSignal().update_instruments.connect(self.update_instruments)