# -*- coding: utf-8 -*- import datetime import json import time import requests import twstock import sys from twstock.proxy import get_proxies SESSION_URL = 'http://mis.twse.com.tw/stock/index.jsp' STOCKINFO_URL = 'http://mis.twse.com.tw/stock/api/getStockInfo.jsp?ex_ch={stock_id}&_={time}' # Mock data mock = False def _format_stock_info(data) -> dict: result = { 'timestamp': 0.0, 'info': {}, 'realtime': {} } # Timestamp result['timestamp'] = int(data['tlong']) / 1000 # Information result['info']['code'] = data['c'] result['info']['channel'] = data['ch'] result['info']['name'] = data['n'] result['info']['fullname'] = data['nf'] result['info']['time'] = datetime.datetime.fromtimestamp( int(data['tlong']) / 1000).strftime('%Y-%m-%d %H:%M:%S') # Process best result def _split_best(d): if d: return d.strip('_').split('_') return d # Realtime information result['realtime']['latest_trade_price'] = data.get('z', None) result['realtime']['trade_volume'] = data.get('tv', None) result['realtime']['accumulate_trade_volume'] = data.get('v', None) result['realtime']['best_bid_price'] = _split_best(data.get('b', None)) result['realtime']['best_bid_volume'] = _split_best(data.get('g', None)) result['realtime']['best_ask_price'] = _split_best(data.get('a', None)) result['realtime']['best_ask_volume'] = _split_best(data.get('f', None)) result['realtime']['open'] = data.get('o', None) result['realtime']['high'] = data.get('h', None) result['realtime']['low'] = data.get('l', None) # Success fetching result['success'] = True return result def _join_stock_id(stocks) -> str: if isinstance(stocks, list): return '|'.join(['{}_{}.tw'.format( 'tse' if s in twstock.twse else 'otc', s) for s in stocks]) return '{}_{stock_id}.tw'.format( 'tse' if stocks in twstock.twse else 'otc', stock_id=stocks) def get_raw(stocks) -> dict: req = requests.Session() req.get(SESSION_URL, proxies=get_proxies()) r = req.get( STOCKINFO_URL.format( stock_id=_join_stock_id(stocks), time=int(time.time()) * 1000)) if sys.version_info < (3, 5): try: return r.json() except ValueError: return {'rtmessage': 'json decode error', 'rtcode': '5000'} else: try: return r.json() except json.decoder.JSONDecodeError: return {'rtmessage': 'json decode error', 'rtcode': '5000'} def get(stocks, retry=3): # Prepare data data = get_raw(stocks) if not mock else twstock.mock.get(stocks) # Set success data['success'] = False # JSONdecode error, could be too fast, retry if data['rtcode'] == '5000': # XXX: Stupit retry, you will dead here if retry: return get(stocks, retry - 1) return data # No msgArray, dead if 'msgArray' not in data: return data # Check have data if not len(data['msgArray']): data['rtmessage'] = 'Empty Query.' data['rtcode'] = '5001' return data # Return multiple stock data if isinstance(stocks, list): result = { data['info']['code']: data for data in map(_format_stock_info, data['msgArray']) } result['success'] = True return result return _format_stock_info(data['msgArray'][0])