Exemple #1
0
def sync_collections():
    from ybk.config import setup_config
    from ybk.models import Collection as C1
    from ybk.models import Quote as Q1
    setup_config()
    for c in C1.query():
        print(c.exchange, c.symbol)
        td = Q1.count({'exchange': c.exchange,
                       'symbol': c.symbol,
                       'type_': '1d'}) + 1
        if td == 1:
            if not c.offers_at:
                # 没录入过, 基本上会挂
                continue

            # 如果K线不存在, 可能是交易行情无法获取, 直接用估算数字
            td = (datetime.utcnow() - c.offers_at).days - 1

        c2 = Collection({
            'exchange': c.exchange,
            'symbol': c.symbol,
            'name': c.name,
            'trade_day': td,
        })
        c2.upsert()
Exemple #2
0
def parse():
    nav = 'parse'
    url = request.args.get('url')
    num_parsed = Announcement.count({
        'parsed': True,
        'type_': {
            '$in': ['offer', 'result']
        }
    })
    num_total = Announcement.count({'type_': {'$in': ['offer', 'result']}})
    if url:
        announcement = Announcement.query_one({'url': url})
        colls = list(Collection.query({'from_url': url}))
        for coll in colls:
            if coll.offers_at:
                coll.offers_at2 = coll.offers_at.strftime('%Y%m%d')
            if coll.offer_cash_ratio:
                coll.offer_cash_ratio = '{:2.0f}%'.format(
                    coll.offer_cash_ratio * 100)
            if coll.offer_price:
                coll.offer_price = str(coll.offer_price)
                if coll.offer_price.endswith('.0'):
                    coll.offer_price = coll.offer_price[:-2]
    all_done = num_parsed == num_total
    return render_template('admin/parse.html', **locals())
Exemple #3
0
def load_symbols():
    exchange = request.args.get('exchange', '')
    query = request.args.get('query', '')
    exclude = request.args.get('exclude', '')
    cond = {
        '$or': [{
            'name': {
                '$regex': query
            }
        }, {
            'symbol': {
                '$regex': query
            }
        }]
    }
    if exchange:
        cond['exchange'] = exchange
    result = [
        {
            'text': '{}({})'.format(c.symbol, c.name),
            'value': c.symbol
        }  # '{}-{}'.format(c.symbol, c.name)}
        for c in Collection.query(cond, {
            'name': 1,
            'symbol': 1
        })
    ]
    if exclude:
        result = [r for r in result if exclude not in r['text']]
    return jsonify(result=result)
Exemple #4
0
def parse_save():
    exchange = request.form.get('exchange')
    status = request.form.get('status', '申购中')
    from_url = request.form.get('from_url')
    type_ = request.form.get('type')
    result = json.loads(request.form.get('result', []))

    if not exchange:
        return jsonify(status=500, reason="字段不全")

    from_url = html.unescape(from_url)

    if type_ == 'offer':
        for coll in result:
            coll['exchange'] = exchange
            coll['status'] = status
            coll['from_url'] = from_url
            coll['offer_quantity'] = int(coll['offer_quantity'])
            coll['offer_price'] = float(coll['offer_price'])
            coll['offers_at'] = datetime.strptime(coll['offers_at'], '%Y%m%d')
            coll['offer_cash_ratio'] = int(coll['offer_cash_ratio'].replace(
                '%', '')) / 100.
            Collection(coll).upsert()

        Announcement.update_one({'_id': from_url}, {'$set': {'parsed': True}})
    elif type_ == 'result':
        for coll in result:
            coll['exchange'] = exchange
            coll['status'] = status
            coll['from_url'] = from_url
            if coll.get('invest_cash'):
                coll['invest_cash'] = float(coll['invest_cash'])
            else:
                del coll['invest_cash']
            if coll.get('invest_cash_return_ratio'):
                coll['invest_cash_return_ratio'] = float(
                    coll['invest_cash_return_ratio'].replace('%', '')) / 100.
            else:
                del coll['invest_cash_return_ratio']
            Collection(coll).upsert()

        Announcement.update_one({'_id': from_url}, {'$set': {'parsed': True}})
    return jsonify(status=200)
Exemple #5
0
def realtime(site):
    conf = get_conf(site)
    exchange = conf['abbr']
    url = conf['quote']['realtime']['url']
    type_ = conf['quote']['realtime']['type']
    today = datetime.utcnow().replace(
        minute=0, second=0, microsecond=0) + timedelta(hours=8)

    if not url:
        log.warning('{}尚未配置实时行情url'.format(exchange))
        return
    if today.hour < 9 or today.hour > 22:
        log.warning('不在9点到22点之间, 不做解析')
        return

    today = today.replace(hour=0)
    text = session.get(url, timeout=(3, 7)).text
    quotes = parse_quotes(type_, text)
    saved = 0
    for q in quotes:
        Collection.update_one({'exchange': exchange,
                               'symbol': q['symbol'].strip()},
                              {'$set': {'name': q['name']}},
                              upsert=True)
        q['exchange'] = exchange
        q['quote_type'] = '1d'
        q['quote_at'] = today
        if q['open_'] in ['—', '-', None, '']:
            continue
        else:
            # 找到上一个交易日的数据, 如果和lclose不符则舍弃
            # 需要保证数据每天更新/不足时需要把日线补足才能正常显示
            lq = Quote.query_one({'exchange': exchange,
                                  'symbol': q['symbol'].strip(),
                                  'quote_type': '1d',
                                  'quote_at': {'$lt': today}},
                                 sort=[('quote_at', -1)])
            if not lq or abs(lq.close - q['lclose']) < 0.01:
                Quote(q).upsert()
                saved += 1

    log.info('{} 导入 {}/{} 条实时交易记录'.format(exchange, saved, len(quotes)))
Exemple #6
0
def history_sysframe(exchange, url, force):
    for c in Collection.query({'exchange': exchange}):
        try:
            if not force and history_exists(c):
                continue

            # 拿到数据文件
            theurl = ('{}/hqApplet/data/day/00{}.day.zip').format(
                url, c.symbol)
            log.info('fetching exchange {} url {}'.format(exchange, theurl))
            r = session.get(
                theurl, timeout=(5, 10), verify=False)
            if r.status_code != 200:
                log.warning('{}_{}下载失败, 错误码: {}'
                            ''.format(exchange, c.symbol, r.status_code))
                continue
            content = gzip.decompress(r.content)

            # 解析之
            num_rows = struct.unpack('>i', content[0:4])[0]
            kline_days = []
            for i in range(num_rows):
                raw_row = content[4 + 40 * i: 4 + 40 * i + 40]
                row = struct.unpack('>i5f2ifi', raw_row)
                t = row[0]
                date = datetime(year=int(str(t)[0:2]) + 1997,
                                month=int(str(t)[2:4]),
                                day=int(str(t)[4:6]),
                                minute=int(str(t)[6:8] or 0),
                                second=int(str(t)[8:10] or 0))
                # row[6]总是0, 不知道是啥
                q = {
                    'exchange': exchange,
                    'symbol': c.symbol,
                    'quote_type': '1d',
                    'quote_at': date,
                    'open_': row[1],
                    'high': row[2],
                    'low': row[3],
                    'close': row[4],
                    'mean': row[5],
                    'volume': row[7],
                    'amount': row[8],
                    'quantity': row[9],
                }
                if kline_days:
                    q['lclose'] = kline_days[-1]['close']
                    save_quotes(q, c, first_quote=False)
                else:
                    save_quotes(q, c, first_quote=True)
                kline_days.append(q)
        except:
            log.exception('{}:{} 抓取失败'.format(c.exchange, c.symbol))
Exemple #7
0
def history_sysframe(exchange, url, force):
    for c in Collection.query({'exchange': exchange}):
        try:
            if not force and history_exists(c):
                continue

            # 拿到数据文件
            theurl = ('{}/hqApplet/data/day/00{}.day.zip').format(
                url, c.symbol)
            log.info('fetching exchange {} url {}'.format(exchange, theurl))
            r = session.get(theurl, timeout=(5, 10), verify=False)
            if r.status_code != 200:
                log.warning('{}_{}下载失败, 错误码: {}'
                            ''.format(exchange, c.symbol, r.status_code))
                continue
            content = gzip.decompress(r.content)

            # 解析之
            num_rows = struct.unpack('>i', content[0:4])[0]
            kline_days = []
            for i in range(num_rows):
                raw_row = content[4 + 40 * i:4 + 40 * i + 40]
                row = struct.unpack('>i5f2ifi', raw_row)
                t = row[0]
                date = datetime(year=int(str(t)[0:2]) + 1997,
                                month=int(str(t)[2:4]),
                                day=int(str(t)[4:6]),
                                minute=int(str(t)[6:8] or 0),
                                second=int(str(t)[8:10] or 0))
                # row[6]总是0, 不知道是啥
                q = {
                    'exchange': exchange,
                    'symbol': c.symbol,
                    'quote_type': '1d',
                    'quote_at': date,
                    'open_': row[1],
                    'high': row[2],
                    'low': row[3],
                    'close': row[4],
                    'mean': row[5],
                    'volume': row[7],
                    'amount': row[8],
                    'quantity': row[9],
                }
                if kline_days:
                    q['lclose'] = kline_days[-1]['close']
                    save_quotes(q, c, first_quote=False)
                else:
                    save_quotes(q, c, first_quote=True)
                kline_days.append(q)
        except:
            log.exception('{}:{} 抓取失败'.format(c.exchange, c.symbol))
Exemple #8
0
def analysis():
    nav = 'analysis'
    exchange = request.args.get('exchange')
    exs = sorted(list(Exchange.query()), key=lambda x: x.abbr)
    exchanges = [e.abbr for e in exs]
    ratings = [ex.rating for ex in exs]
    if not exchange:
        exchange = exchanges[0]
    ex = None
    for ex in exs:
        if ex.abbr == exchange:
            break

    # invest history
    ih_dates = []
    ih_values_self = []
    ih_values_all = []
    for h in ex.invest_cash_history:
        ih_dates.append(h['date'].strftime('%Y-%m-%d'))
        ih_values_self.append(h['invest_cash'] / 1e8)
        ih_values_all.append(h['total_cash'] / 1e8)

    # increase history
    inc_days = []
    inc_series = []
    symbols = []
    for symbol, values in ex.increase_history.items():
        if len(values) > len(inc_days):
            inc_days = list(range(1, len(values)))
        inc_series.append({
            'name': symbol,
            'type': 'line',
            'data': [v * 100 for v in values],
        })
        symbols.append(symbol)

    # predict
    conf = get_conf(ex.abbr)
    today = datetime.utcnow() + timedelta(hours=8)
    today = today.replace(hour=0, minute=0, second=0, microsecond=0)
    before = today - timedelta(days=conf['cashout'])
    cashout_at = today + timedelta(days=conf['cashout'])
    colls = list(
        Collection.query({
            'exchange': ex.abbr,
            'offers_at': {
                '$gte': before
            }
        }))
    locals()['zip'] = zip
    return render_template('frontend/analysis.html', **locals())
Exemple #9
0
def collection():
    nav = 'collection'

    search = request.args.get('search', '')
    exchange = request.args.get('exchange', '')
    page = int(request.args.get('page', 1) or 1)

    limit = 25
    skip = limit * (page - 1)
    cond = {}
    if exchange:
        cond['exchange'] = exchange
    total = Collection.count(cond)
    pagination = Pagination(page, limit, total)

    collections = list(
        Collection.query(cond,
                         sort=[('offers_at', -1)],
                         skip=skip, limit=limit))
    for c in collections:
        lp = Quote.latest_price(c.exchange, c.symbol)
        if lp and c.offer_price:
            c.total_increase = lp / c.offer_price - 1
    return render_template('frontend/collection.html', **locals())
Exemple #10
0
def load_symbols():
    exchange = request.args.get('exchange', '')
    query = request.args.get('query', '')
    exclude = request.args.get('exclude', '')
    cond = {'$or': [{'name': {'$regex': query}},
                    {'symbol': {'$regex': query}}]}
    if exchange:
        cond['exchange'] = exchange
    result = [
        {'text': '{}({})'.format(c.symbol, c.name),
         'value': c.symbol}  # '{}-{}'.format(c.symbol, c.name)}
        for c in Collection.query(
            cond,
            {'name': 1, 'symbol': 1})]
    if exclude:
        result = [r for r in result if exclude not in r['text']]
    return jsonify(result=result)
Exemple #11
0
def analysis():
    nav = 'analysis'
    exchange = request.args.get('exchange')
    exs = sorted(list(Exchange.query()), key=lambda x: x.abbr)
    exchanges = [e.abbr for e in exs]
    ratings = [ex.rating for ex in exs]
    if not exchange:
        exchange = exchanges[0]
    ex = None
    for ex in exs:
        if ex.abbr == exchange:
            break

    # invest history
    ih_dates = []
    ih_values_self = []
    ih_values_all = []
    for h in ex.invest_cash_history:
        ih_dates.append(h['date'].strftime('%Y-%m-%d'))
        ih_values_self.append(h['invest_cash'] / 1e8)
        ih_values_all.append(h['total_cash'] / 1e8)

    # increase history
    inc_days = []
    inc_series = []
    symbols = []
    for symbol, values in ex.increase_history.items():
        if len(values) > len(inc_days):
            inc_days = list(range(1, len(values)))
        inc_series.append({
            'name': symbol,
            'type': 'line',
            'data': [v * 100 for v in values],
        })
        symbols.append(symbol)

    # predict
    conf = get_conf(ex.abbr)
    today = datetime.utcnow() + timedelta(hours=8)
    today = today.replace(hour=0, minute=0, second=0, microsecond=0)
    before = today - timedelta(days=conf['cashout'])
    cashout_at = today + timedelta(days=conf['cashout'])
    colls = list(Collection.query({'exchange': ex.abbr,
                                   'offers_at': {'$gte': before}}))
    locals()['zip'] = zip
    return render_template('frontend/analysis.html', **locals())
Exemple #12
0
def parse():
    nav = "parse"
    url = request.args.get("url")
    num_parsed = Announcement.count({"parsed": True, "type_": {"$in": ["offer", "result"]}})
    num_total = Announcement.count({"type_": {"$in": ["offer", "result"]}})
    if url:
        announcement = Announcement.query_one({"url": url})
        colls = list(Collection.query({"from_url": url}))
        for coll in colls:
            if coll.offers_at:
                coll.offers_at2 = coll.offers_at.strftime("%Y%m%d")
            if coll.offer_cash_ratio:
                coll.offer_cash_ratio = "{:2.0f}%".format(coll.offer_cash_ratio * 100)
            if coll.offer_price:
                coll.offer_price = str(coll.offer_price)
                if coll.offer_price.endswith(".0"):
                    coll.offer_price = coll.offer_price[:-2]
    all_done = num_parsed == num_total
    return render_template("admin/parse.html", **locals())
Exemple #13
0
def parse(site):
    rabbrs = {v: k for k, v in ABBRS.items()}
    abbr = rabbrs[site]
    parser = importlib.__import__('ybk.parsers.{}'.format(site),
                                  fromlist=['Parser']).Parser()
    log.info('解析交易所 {}'.format(abbr))
    num_parsed = 0
    num_failed = 0
    for a in Announcement.query({'exchange': abbr,
                                 'parsed': {'$ne': True}}):
        log.info('parsing {}'.format(a.url))
        try:
            for c in parser.parse(a.type_, a.html):
                c['from_url'] = a.url
                Collection(c).upsert()
            a.update({'$set': {'parsed': True}})
            num_parsed += 1
        except Exception as e:
            num_failed += 1
            if not isinstance(e, NotImplementedError):
                log.exception('解析错误')
            continue

    log.info('解析完毕, {}个成功, {}个失败'.format(num_parsed, num_failed))
Exemple #14
0
def history_winner(exchange, url, force):
    assert url.startswith('tcp://')
    host, port = url[6:].split(':')
    port = int(port)
    s = socket.socket()
    s.connect((host, port))

    def get_day_data(symbol):
        bsymbol = symbol.encode('utf-8')
        bizdata = b''.join([
            b'\xfe\x8f\x00\x00',
            b'\x00' * 12,
            b'\x01\x00',
            b',\x00',
            b'\x02\x04',
            b'\x00',
            b'\x00',
            b'\x00\x00\x00\x00',
            b'\x013' + bsymbol,
            b'\x03\x00',
            b'\x00\x00',
            b'\x00\x00\x00\x00\x00\x00\x00\x00',
            b'Z\x00\x10\x00\x013' + bsymbol,
            b'\x00\x00\x00\x00',
            b'\x00',
            b'\x00',
        ])
        bdata = b''.join([
            b'\x95\x00\x00\x95',
            b'11=524\x00',
            b'13=8\x00',
            b'5=36862\x00',
            b'4=109\x00',
            b'1=66\x008=',
            bizdata,
            b'\x00',
            b'1=40\x0069=markid=60ba7308cab942ee961536a74ec7c5f9\x00\x00',
        ])
        s.sendall(bdata)
        batch = 8192
        result = []
        while True:
            result.append(s.recv(batch))
            if len(result[-1]) != batch:
                break
        return b''.join(result)

    def parse_day_data(data):
        size = struct.unpack('>i', b'\x00' + data[1:4])[0]
        assert size + 4 == len(data)
        m = re.compile(b'1=(\d+)\x008=').search(data)
        if m:
            bizsize = int(m.group(1))
            start = m.span()[1]
            try:
                bbiz = zlib.decompress(data[start:start + bizsize])
            except:
                bbiz = data[start:start + bizsize]
            assert bbiz[:4] == b'\xfe\x8f\x00\x00'
            num_packs = struct.unpack('<H', bbiz[16:18])[0]
            sizes = [
                struct.unpack('<H', bbiz[18 + 2 * i:20 + 2 * i])[0]
                for i in range(num_packs)
            ]

            for i in range(num_packs):
                start = 18 + 2 * num_packs + 0 if i == 0 else sizes[i - 1]
                if bbiz[start:start + 2] == b'\x02\x04':
                    # K线数据
                    symbol = bbiz[start + 10:start + 16].decode('utf-8')
                    count = struct.unpack('<I', bbiz[start + 16:start + 20])[0]
                    kline_days = []
                    for i in range(count):
                        begin = start + 20 + i * 32
                        row = struct.unpack('<Iiiiiiii',
                                            bbiz[begin:begin + 32])
                        q = {
                            'exchange': exchange,
                            'symbol': symbol,
                            'quote_type': '1d',
                            'quote_at':
                            datetime.strptime(str(row[0]), "%Y%m%d"),
                            'open_': row[1] / 100,
                            'high': row[2] / 100,
                            'low': row[3] / 100,
                            'close': row[4] / 100,
                            'amount': row[5] / 1.,
                            'volume': row[6],
                        }
                        if kline_days:
                            q['lclose'] = kline_days[-1]['close']
                            save_quotes(q, c, first_quote=False)
                        else:
                            save_quotes(q, c, first_quote=True)
                        kline_days.append(q)

    for c in Collection.query({'exchange': exchange}):
        try:
            if not force and history_exists(c):
                continue
            if '$' not in c.symbol:
                log.info('feching {}_{} on {}'.format(c.exchange, c.symbol,
                                                      url))
                data = get_day_data(c.symbol)
                parse_day_data(data)
        except:
            log.exception('{}_{}获取失败'.format(exchange, c.symbol))
Exemple #15
0
def collection_list():
    exchange = request.args.get('exchange', '')
    search = request.args.get('search', '')
    sort = request.args.get('sort', 'offers_at')
    order = request.args.get('order', 'desc')

    limit = int(request.args.get('limit', 25))
    offset = int(request.args.get('offset', 0))
    if sort in ['offers_at', 'exchange', 'name', 'symbol',
                'offer_price', 'offer_quantity']:
        dbsort = [(sort, 1 if order == 'asc' else -1)]
    else:
        dbsort = None

    cond = {}
    if exchange:
        cond['exchange'] = exchange
    if search:
        cond['$or'] = [
            {'exchange': {'$regex': search}},
            {'name': {'$regex': search}},
            {'symbol': {'$regex': search}},
        ]
    total = Collection.count(cond)
    qs = Collection.find(cond)
    if dbsort:
        qs = [Collection(c) for c in
              qs.sort(dbsort).skip(offset).limit(limit)]
    rows = [{
            'offers_at': c.offers_at,
            'exchange': c.exchange,
            'name': c.name,
            'symbol': c.symbol,
            'offer_price': c.offer_price,
            'offer_quantity': c.offer_quantity,
            'offer_cash_ratio': c.offer_cash_ratio,
            'offer_cash': c.offer_cash,
            'result_ratio_cash': c.result_ratio_cash,
            }
            for c in qs]

    for d in rows:
        d['total_increase'] = None
        lp = Quote.latest_price(d['exchange'], d['symbol'])
        if lp and d['offer_price']:
            d['total_increase'] = lp / d['offer_price'] - 1

    if not dbsort:
        rows = sorted(rows,
                      key=lambda x: x.get(sort) or 0,
                      reverse=order == 'desc')
        rows = rows[offset:offset + limit]

    for d in rows:
        d['offers_at'] = d['offers_at'].strftime(
            '%Y-%m-%d') if d['offers_at'] else None

        if d['offer_price']:
            d['offer_price'] = '{:.2f}'.format(d['offer_price'])

        if d['offer_cash_ratio']:
            d['offer_cash_ratio'] = '{:.0f}%'.format(
                d['offer_cash_ratio'] * 100)

        if d['offer_cash']:
            d['offer_cash'] = '{:.1f}'.format(d['offer_cash'])

        if d['result_ratio_cash']:
            d['result_ratio_cash'] = '{:.3f}%'.format(
                d['result_ratio_cash'] * 100)

        if d['total_increase']:
            d['total_increase'] = '{:.1f}%'.format(
                100 * (d['total_increase']))

    return jsonify(total=total, rows=rows)
Exemple #16
0
def history_winner(exchange, url, force):
    assert url.startswith('tcp://')
    host, port = url[6:].split(':')
    port = int(port)
    s = socket.socket()
    s.connect((host, port))

    def get_day_data(symbol):
        bsymbol = symbol.encode('utf-8')
        bizdata = b''.join([
            b'\xfe\x8f\x00\x00', b'\x00' * 12,
            b'\x01\x00',
            b',\x00',
            b'\x02\x04', b'\x00', b'\x00', b'\x00\x00\x00\x00',
            b'\x013' + bsymbol,
            b'\x03\x00', b'\x00\x00',
            b'\x00\x00\x00\x00\x00\x00\x00\x00',
            b'Z\x00\x10\x00\x013' + bsymbol, b'\x00\x00\x00\x00',
            b'\x00', b'\x00',
        ])
        bdata = b''.join([
            b'\x95\x00\x00\x95',
            b'11=524\x00',
            b'13=8\x00',
            b'5=36862\x00',
            b'4=109\x00',
            b'1=66\x008=', bizdata, b'\x00',
            b'1=40\x0069=markid=60ba7308cab942ee961536a74ec7c5f9\x00\x00',
        ])
        s.sendall(bdata)
        batch = 8192
        result = []
        while True:
            result.append(s.recv(batch))
            if len(result[-1]) != batch:
                break
        return b''.join(result)

    def parse_day_data(data):
        size = struct.unpack('>i', b'\x00' + data[1:4])[0]
        assert size + 4 == len(data)
        m = re.compile(b'1=(\d+)\x008=').search(data)
        if m:
            bizsize = int(m.group(1))
            start = m.span()[1]
            try:
                bbiz = zlib.decompress(data[start: start + bizsize])
            except:
                bbiz = data[start: start + bizsize]
            assert bbiz[:4] == b'\xfe\x8f\x00\x00'
            num_packs = struct.unpack('<H', bbiz[16:18])[0]
            sizes = [struct.unpack('<H',
                                   bbiz[18 + 2 * i: 20 + 2 * i])[0]
                     for i in range(num_packs)]

            for i in range(num_packs):
                start = 18 + 2 * num_packs + 0 if i == 0 else sizes[i - 1]
                if bbiz[start:start + 2] == b'\x02\x04':
                    # K线数据
                    symbol = bbiz[start + 10: start + 16].decode('utf-8')
                    count = struct.unpack(
                        '<I', bbiz[start + 16: start + 20])[0]
                    kline_days = []
                    for i in range(count):
                        begin = start + 20 + i * 32
                        row = struct.unpack('<Iiiiiiii',
                                            bbiz[begin: begin + 32])
                        q = {
                            'exchange': exchange,
                            'symbol': symbol,
                            'quote_type': '1d',
                            'quote_at': datetime.strptime(str(row[0]),
                                                          "%Y%m%d"),
                            'open_': row[1] / 100,
                            'high': row[2] / 100,
                            'low': row[3] / 100,
                            'close': row[4] / 100,
                            'amount': row[5] / 1.,
                            'volume': row[6],
                        }
                        if kline_days:
                            q['lclose'] = kline_days[-1]['close']
                            save_quotes(q, c, first_quote=False)
                        else:
                            save_quotes(q, c, first_quote=True)
                        kline_days.append(q)

    for c in Collection.query({'exchange': exchange}):
        try:
            if not force and history_exists(c):
                continue
            if '$' not in c.symbol:
                log.info('feching {}_{} on {}'.format(c.exchange, c.symbol, url))
                data = get_day_data(c.symbol)
                parse_day_data(data)
        except:
            log.exception('{}_{}获取失败'.format(exchange, c.symbol))
Exemple #17
0
def update_trade_account(trade_account):
    ta = trade_account
    log.info('更新账号{}的信息'.format(ta._id))
    if not ta.login_password:
        ta.verified = False
        ta.verify_message = '没有密码不能登录'
    else:
        try:
            t = Trader(ta.exchange, ta.login_name, ta.login_password)
        except KeyError:
            ta.verified = False
            ta.verify_message = '该交易所协议未破解'
        except Exception as e:
            ta.verified = False
            ta.verify_message = str(e)
        else:
            if not t.is_logged_in:
                ta.verified = False
                ta.verify_message = t.last_error
            else:
                ta.verified = True

                # update money
                ta.money = t.money()
                # update position
                position = t.position()
                if position is not None:
                    for p in position:
                        p['name'] = Collection.get_name(
                            ta.exchange, p['symbol']) or ''
                    ta.position = position

                # update orders
                orders = t.orders()
                aggorders = {}
                for o in orders:
                    o['name'] = Collection.get_name(
                        ta.exchange, o['symbol']) or ''
                    st = (o['symbol'], o['type_'])
                    if st not in aggorders:
                        aggorders[st] = o
                    else:
                        # 把成交汇总一下
                        oo = aggorders[st]
                        if oo['quantity'] > 0:
                            amount = oo['price'] * oo['quantity'] + \
                                o['price'] * o['quantity']
                            oo['quantity'] += o['quantity']
                            oo['price'] = amount / oo['quantity']

                orders = aggorders.values()

                ta.orders = orders

                # update order_status
                order_status = t.order_status()
                for o in order_status:
                    o['name'] = Collection.get_name(
                        ta.exchange, o['symbol']) or ''
                ta.order_status = order_status

    ta.upsert()
    user = User.query_one({'_id': ta.user})
    accounting(user)
Exemple #18
0
def trade_quote_history():
    """ K线数据 """
    exchange = request.args.get('exchange', '')
    symbol = request.args.get('symbol', '')
    c = Collection.query_one({'exchange': exchange, 'symbol': symbol})
    period = request.args.get('period', '1d')

    # chart1
    qs = list(Quote.cached(3600).query({'exchange': exchange,
                                        'symbol': symbol,
                                        'quote_type': period}))

    name = '{}({}_{})'.format(Collection.get_name(exchange, symbol),
                              exchange, symbol)
    xdata = [q.quote_at.strftime('%Y/%m/%d') for q in qs]
    sdata = [
        (q.open_, q.close, q.low, q.high,)
        for q in qs]
    adata = [int(q.amount / 10000) for q in qs]
    num_prefix = 100 - len(xdata)
    if num_prefix > 0:
        xdata = xdata + [''] * num_prefix
        sdata = sdata + [()] * num_prefix
        adata = adata + [0] * num_prefix
    option1 = {
        'title': {
            'text': name
        },
        'xAxis': [{
            'type': 'category',
            'boundaryGap': True,
            'axisTick': {'onGap': False},
            'splitLine': {'show': False},
            'data': xdata,
        }],
        'legend': {
            'data': [name, '成交额(万)']
        },
        'dataZoom': {
            'show': False,
            'realtime': True,
            'start': (len(adata) - 100) * 100 // len(adata),
            'end': 100
        },
        'series': [
            {'name': '{}({}_{})'.format(c.name, c.exchange, c.symbol),
             'type': 'k',
             'data': sdata,
             },
            {'name': '成交额(万)',
             'type': 'bar',
             'symbol': 'none',
             'data': [],
             },
        ],
    }

    # chart2
    option2 = {
        'title': {
            'text': '',
        },
        'toolbox': {
            'y': -30,
            'show': True,
            'feature': {
                'mark': {'show': True},
                'dataZoom': {'show': True},
                'dataView': {'show': True, 'readOnly': False},
                'magicType': {'show': True, 'type': ['line', 'bar']},
                'restore': {'show': True},
                'saveAsImage': {'show': True}
            }
        },
        'tooltip': {
            'trigger': 'axis',
            'showDelay': 0,
        },
        'legend': {
            'y': -30,
            'data': ['成交额(万)'],
        },
        'xAxis': [
            {
                'type': 'category',
                'position': 'top',
                'boundaryGap': True,
                'axisLabel': {'show': False},
                'axisTick': {'onGap': False},
                'splitLine': {'show': False},
                'data': xdata,
            }
        ],
        'yAxis': {
            'splitNumber': 3,
        },
        'series': [
            {
                'name': '成交额(万)',
                'type': 'bar',
                'symbol': 'none',
                'data': adata,
            }
        ],
        'grid': {
            'x': 80,
            'y': 5,
            'x2': 20,
            'y2': 40
        },
        'dataZoom': {
            'show': True,
            'realtime': True,
            'start': (len(adata) - 100) * 100 // len(adata),
            'end': 100
        },
    }
    return jsonify(status=200,
                   option1=option1,
                   option2=option2)
Exemple #19
0
def trade_quote_realtime():
    """ 实时数据/列表 """
    # 全部 -> all
    # 指数 -> index
    # 持仓 -> position
    # 自选 -> diy
    category = request.args.get('category', '').strip()
    search = request.args.get('search', '').strip()
    sort = request.args.get('sort', '').strip()
    order = request.args.get('order', 'asc').strip()

    today = Quote.cached(3600).query_one({
        'quote_type': '1d'
    },
                                         sort=[('quote_at', -1)]).quote_at
    cond = {'quote_type': '1d', 'quote_at': today}
    colls = set()
    symbols = []
    if search:
        pairs = Collection.search(search)
        symbols = [p[1] for p in pairs]
        colls = set(pairs)
        cond['symbol'] = {'$in': symbols}
    elif category == 'all':
        pass
    elif category == 'index':
        cs = list(Collection.cached(3600).query({'name': {'$regex': '指数$'}}))
        colls = set((c.exchange, c.symbol) for c in cs)
        symbols = [c.symbol for c in cs]
        cond['symbol'] = {'$in': symbols}
    elif category == 'position':
        position = Position.user_position(current_user._id)
        colls = set((p['exchange'], p['symbol']) for p in position)
        symbols = [p['symbol'] for p in position]
        cond['symbol'] = {'$in': symbols}
    elif category == 'diy':
        raise NotImplementedError

    qs = [
        q for q in Quote.query(cond)
        if (not colls) or ((q.exchange, q.symbol) in colls)
    ]

    qs = [{
        'open_': q.open_,
        'high': q.high,
        'low': q.low,
        'close': q.close,
        'lclose': q.lclose,
        'volume': q.volume,
        'amount': q.amount,
        'increase': 0 if not q.lclose else q.close / q.lclose - 1,
        'exchange': q.exchange,
        'symbol': q.symbol,
        'name': Collection.get_name(q.exchange, q.symbol),
    } for q in qs]

    # sort
    if sort:
        qs = sorted(qs, key=lambda x: x[sort], reverse=order == 'desc')

    # format
    for q in qs:
        if q['lclose']:
            q['lclose'] = '{:.2f}'.format(q['lclose'])
        q['open_'] = '{:.2f}'.format(q['open_'])
        q['high'] = '{:.2f}'.format(q['high'])
        q['low'] = '{:.2f}'.format(q['low'])
        q['close'] = '{:.2f}'.format(q['close'])
        q['amount'] = '{:.1f}万'.format(q['amount'] / 10000)
        q['increase'] = '{:.1f}%'.format(q['increase'] * 100)

    # add no result symbols
    exist_pairs = set((q['exchange'], q['symbol']) for q in qs)
    for exchange, symbol in (colls - exist_pairs):
        qs.append({
            'open_': '-',
            'high': '-',
            'low': '-',
            'close': '-',
            'lclose': '-',
            'volume': '-',
            'amount': '-',
            'increase': '-',
            'exchange': exchange,
            'symbol': symbol,
            'name': Collection.get_name(exchange, symbol),
        })

    return jsonify(status=200, total=len(qs), rows=qs)
Exemple #20
0
def trade_quote_history():
    """ K线数据 """
    exchange = request.args.get('exchange', '')
    symbol = request.args.get('symbol', '')
    c = Collection.query_one({'exchange': exchange, 'symbol': symbol})
    period = request.args.get('period', '1d')

    # chart1
    qs = list(
        Quote.cached(3600).query({
            'exchange': exchange,
            'symbol': symbol,
            'quote_type': period
        }))

    name = '{}({}_{})'.format(Collection.get_name(exchange, symbol), exchange,
                              symbol)
    xdata = [q.quote_at.strftime('%Y/%m/%d') for q in qs]
    sdata = [(
        q.open_,
        q.close,
        q.low,
        q.high,
    ) for q in qs]
    adata = [int(q.amount / 10000) for q in qs]
    num_prefix = 100 - len(xdata)
    if num_prefix > 0:
        xdata = xdata + [''] * num_prefix
        sdata = sdata + [()] * num_prefix
        adata = adata + [0] * num_prefix
    option1 = {
        'title': {
            'text': name
        },
        'xAxis': [{
            'type': 'category',
            'boundaryGap': True,
            'axisTick': {
                'onGap': False
            },
            'splitLine': {
                'show': False
            },
            'data': xdata,
        }],
        'legend': {
            'data': [name, '成交额(万)']
        },
        'dataZoom': {
            'show': False,
            'realtime': True,
            'start': (len(adata) - 100) * 100 // len(adata),
            'end': 100
        },
        'series': [
            {
                'name': '{}({}_{})'.format(c.name, c.exchange, c.symbol),
                'type': 'k',
                'data': sdata,
            },
            {
                'name': '成交额(万)',
                'type': 'bar',
                'symbol': 'none',
                'data': [],
            },
        ],
    }

    # chart2
    option2 = {
        'title': {
            'text': '',
        },
        'toolbox': {
            'y': -30,
            'show': True,
            'feature': {
                'mark': {
                    'show': True
                },
                'dataZoom': {
                    'show': True
                },
                'dataView': {
                    'show': True,
                    'readOnly': False
                },
                'magicType': {
                    'show': True,
                    'type': ['line', 'bar']
                },
                'restore': {
                    'show': True
                },
                'saveAsImage': {
                    'show': True
                }
            }
        },
        'tooltip': {
            'trigger': 'axis',
            'showDelay': 0,
        },
        'legend': {
            'y': -30,
            'data': ['成交额(万)'],
        },
        'xAxis': [{
            'type': 'category',
            'position': 'top',
            'boundaryGap': True,
            'axisLabel': {
                'show': False
            },
            'axisTick': {
                'onGap': False
            },
            'splitLine': {
                'show': False
            },
            'data': xdata,
        }],
        'yAxis': {
            'splitNumber': 3,
        },
        'series': [{
            'name': '成交额(万)',
            'type': 'bar',
            'symbol': 'none',
            'data': adata,
        }],
        'grid': {
            'x': 80,
            'y': 5,
            'x2': 20,
            'y2': 40
        },
        'dataZoom': {
            'show': True,
            'realtime': True,
            'start': (len(adata) - 100) * 100 // len(adata),
            'end': 100
        },
    }
    return jsonify(status=200, option1=option1, option2=option2)
Exemple #21
0
def update_trade_account(trade_account):
    ta = trade_account
    log.info('更新账号{}的信息'.format(ta._id))
    if not ta.login_password:
        ta.verified = False
        ta.verify_message = '没有密码不能登录'
    else:
        try:
            t = Trader(ta.exchange, ta.login_name, ta.login_password)
        except KeyError:
            ta.verified = False
            ta.verify_message = '该交易所协议未破解'
        except Exception as e:
            ta.verified = False
            ta.verify_message = str(e)
        else:
            if not t.is_logged_in:
                ta.verified = False
                ta.verify_message = t.last_error
            else:
                ta.verified = True

                # update money
                ta.money = t.money()
                # update position
                position = t.position()
                if position is not None:
                    for p in position:
                        p['name'] = Collection.get_name(
                            ta.exchange, p['symbol']) or ''
                    ta.position = position

                # update orders
                orders = t.orders()
                aggorders = {}
                for o in orders:
                    o['name'] = Collection.get_name(ta.exchange,
                                                    o['symbol']) or ''
                    st = (o['symbol'], o['type_'])
                    if st not in aggorders:
                        aggorders[st] = o
                    else:
                        # 把成交汇总一下
                        oo = aggorders[st]
                        if oo['quantity'] > 0:
                            amount = oo['price'] * oo['quantity'] + \
                                o['price'] * o['quantity']
                            oo['quantity'] += o['quantity']
                            oo['price'] = amount / oo['quantity']

                orders = aggorders.values()

                ta.orders = orders

                # update order_status
                order_status = t.order_status()
                for o in order_status:
                    o['name'] = Collection.get_name(ta.exchange,
                                                    o['symbol']) or ''
                ta.order_status = order_status

    ta.upsert()
    user = User.query_one({'_id': ta.user})
    accounting(user)
Exemple #22
0
def calendar():
    nav = 'calendar'

    starts_at = request.args.get('starts_at')
    ends_at = request.args.get('ends_at')
    if starts_at:
        starts_at = datetime.strptime(starts_at, '%Y%m%d')

    today = datetime.utcnow() + timedelta(hours=8)
    today = today.replace(hour=0, minute=0, second=0, microsecond=0)
    if not starts_at:
        starts_at = today - timedelta(days=3)
    ends_at = starts_at + timedelta(days=10)

    # 表头
    heads = []
    d = starts_at
    while d <= ends_at:
        heads.append(
            ('周' + '一二三四五六日'[d.weekday()], '{}/{}'.format(d.month, d.day)))
        d += timedelta(days=1)

    # 表身
    exs = []  # 交易所所在行
    rowdict = defaultdict(list)  # 交易所 -> 每天有/没有
    seen = set()
    ddict = {}
    for c in Collection.query(
        {'offers_at': {
            '$gte': starts_at,
            '$lte': ends_at
        }},
            sort=[('offers_at', 1)]):
        if (c.exchange, c.offers_at) in seen:
            continue
        seen.add((c.exchange, c.offers_at))
        if c.exchange not in exs:
            exs.append(c.exchange)
        d = ddict.get(c.exchange, starts_at)
        while d < c.cashout_at:
            if d >= c.offers_at and d < c.cashout_at:
                cs = list(
                    Collection.query({
                        'offers_at': c.offers_at,
                        'exchange': c.exchange
                    }))
                ndays = (c.cashout_at - c.offers_at).days
                if c.offers_at + timedelta(days=ndays) > ends_at:
                    ndays = (ends_at - c.offers_at).days + 1
                rowdict[c.exchange].append({
                    'colspan':
                    ndays,
                    'exchange':
                    c.exchange,
                    'count':
                    len(cs),
                    'cs':
                    cs,
                    'symbols':
                    ','.join([c.symbol for c in cs])
                })
                ddict[c.exchange] = c.cashout_at
                break
            else:
                rowdict[c.exchange].append({'colspan': 1})
                d += timedelta(days=1)

    banks = {}
    details = {}
    for ex in ddict:
        d = ddict[ex]
        while d <= ends_at:
            spans = sum(x['colspan'] for x in rowdict[ex])
            if spans < 11:
                rowdict[ex].append({'colspan': 1})
            d += timedelta(days=1)

        c = get_conf(ex)
        banks[ex] = c['opening']['bank']
        details[ex] = {}
        for cell in rowdict[ex]:
            if 'cs' in cell:
                for c in cell['cs']:
                    details[ex][c.symbol] = {
                        'name': c.name,
                        'price': c.offer_price,
                        'offer_cash': c.offer_cash or 0,
                        'expected_ratio': c.expected_result_cash_ratio or 0,
                        'expected_revenue': c.expected_annual_profit or 0,
                    }

    if not exs:
        exs = ['无申购']

    prev_starts_at = (starts_at - timedelta(days=10)).strftime('%Y%m%d')
    next_starts_at = (starts_at + timedelta(days=10)).strftime('%Y%m%d')

    thisdate = (datetime.utcnow() + timedelta(hours=8))
    thisdate = '{}/{}'.format(thisdate.month, thisdate.day)

    return render_template('frontend/calendar.html', **locals())
Exemple #23
0
def trade_quote_realtime():
    """ 实时数据/列表 """
    # 全部 -> all
    # 指数 -> index
    # 持仓 -> position
    # 自选 -> diy
    category = request.args.get('category', '').strip()
    search = request.args.get('search', '').strip()
    sort = request.args.get('sort', '').strip()
    order = request.args.get('order', 'asc').strip()

    today = Quote.cached(3600).query_one({'quote_type': '1d'},
                                         sort=[('quote_at', -1)]).quote_at
    cond = {'quote_type': '1d',
            'quote_at': today}
    colls = set()
    symbols = []
    if search:
        pairs = Collection.search(search)
        symbols = [p[1] for p in pairs]
        colls = set(pairs)
        cond['symbol'] = {'$in': symbols}
    elif category == 'all':
        pass
    elif category == 'index':
        cs = list(Collection.cached(3600).query({'name': {'$regex': '指数$'}}))
        colls = set((c.exchange, c.symbol) for c in cs)
        symbols = [c.symbol for c in cs]
        cond['symbol'] = {'$in': symbols}
    elif category == 'position':
        position = Position.user_position(current_user._id)
        colls = set((p['exchange'], p['symbol']) for p in position)
        symbols = [p['symbol'] for p in position]
        cond['symbol'] = {'$in': symbols}
    elif category == 'diy':
        raise NotImplementedError

    qs = [q for q in Quote.query(cond)
          if (not colls) or
          ((q.exchange, q.symbol) in colls)]

    qs = [{
        'open_': q.open_,
        'high': q.high,
        'low': q.low,
        'close': q.close,
        'lclose': q.lclose,
        'volume': q.volume,
        'amount': q.amount,
        'increase': 0 if not q.lclose else q.close / q.lclose - 1,
        'exchange': q.exchange,
        'symbol': q.symbol,
        'name': Collection.get_name(q.exchange, q.symbol),
    } for q in qs]

    # sort
    if sort:
        qs = sorted(qs,
                    key=lambda x: x[sort],
                    reverse=order == 'desc')

    # format
    for q in qs:
        if q['lclose']:
            q['lclose'] = '{:.2f}'.format(q['lclose'])
        q['open_'] = '{:.2f}'.format(q['open_'])
        q['high'] = '{:.2f}'.format(q['high'])
        q['low'] = '{:.2f}'.format(q['low'])
        q['close'] = '{:.2f}'.format(q['close'])
        q['amount'] = '{:.1f}万'.format(q['amount'] / 10000)
        q['increase'] = '{:.1f}%'.format(q['increase'] * 100)

    # add no result symbols
    exist_pairs = set((q['exchange'], q['symbol']) for q in qs)
    for exchange, symbol in (colls - exist_pairs):
        qs.append({
            'open_': '-',
            'high': '-',
            'low': '-',
            'close': '-',
            'lclose': '-',
            'volume': '-',
            'amount': '-',
            'increase': '-',
            'exchange': exchange,
            'symbol': symbol,
            'name': Collection.get_name(exchange, symbol),
        })

    return jsonify(status=200,
                   total=len(qs),
                   rows=qs)
Exemple #24
0
def calendar():
    nav = "calendar"

    starts_at = request.args.get("starts_at")
    ends_at = request.args.get("ends_at")
    if starts_at:
        starts_at = datetime.strptime(starts_at, "%Y%m%d")

    today = datetime.utcnow() + timedelta(hours=8)
    today = today.replace(hour=0, minute=0, second=0, microsecond=0)
    if not starts_at:
        starts_at = today - timedelta(days=3)
    ends_at = starts_at + timedelta(days=10)

    # 表头
    heads = []
    d = starts_at
    while d <= ends_at:
        heads.append(("周" + "一二三四五六日"[d.weekday()], "{}/{}".format(d.month, d.day)))
        d += timedelta(days=1)

    # 表身
    exs = []  # 交易所所在行
    rowdict = defaultdict(list)  # 交易所 -> 每天有/没有
    seen = set()
    ddict = {}
    for c in Collection.query({"offers_at": {"$gte": starts_at, "$lte": ends_at}}, sort=[("offers_at", 1)]):
        if (c.exchange, c.offers_at) in seen:
            continue
        seen.add((c.exchange, c.offers_at))
        if c.exchange not in exs:
            exs.append(c.exchange)
        d = ddict.get(c.exchange, starts_at)
        while d < c.cashout_at:
            if d >= c.offers_at and d < c.cashout_at:
                cs = list(Collection.query({"offers_at": c.offers_at, "exchange": c.exchange}))
                ndays = (c.cashout_at - c.offers_at).days
                if c.offers_at + timedelta(days=ndays) > ends_at:
                    ndays = (ends_at - c.offers_at).days + 1
                rowdict[c.exchange].append(
                    {
                        "colspan": ndays,
                        "exchange": c.exchange,
                        "count": len(cs),
                        "cs": cs,
                        "symbols": ",".join([c.symbol for c in cs]),
                    }
                )
                ddict[c.exchange] = c.cashout_at
                break
            else:
                rowdict[c.exchange].append({"colspan": 1})
                d += timedelta(days=1)

    banks = {}
    details = {}
    for ex in ddict:
        d = ddict[ex]
        while d <= ends_at:
            spans = sum(x["colspan"] for x in rowdict[ex])
            if spans < 11:
                rowdict[ex].append({"colspan": 1})
            d += timedelta(days=1)

        c = get_conf(ex)
        banks[ex] = c["opening"]["bank"]
        details[ex] = {}
        for cell in rowdict[ex]:
            if "cs" in cell:
                for c in cell["cs"]:
                    details[ex][c.symbol] = {
                        "name": c.name,
                        "price": c.offer_price,
                        "offer_cash": c.offer_cash or 0,
                        "expected_ratio": c.expected_result_cash_ratio or 0,
                        "expected_revenue": c.expected_annual_profit or 0,
                    }

    if not exs:
        exs = ["无申购"]

    prev_starts_at = (starts_at - timedelta(days=10)).strftime("%Y%m%d")
    next_starts_at = (starts_at + timedelta(days=10)).strftime("%Y%m%d")

    thisdate = datetime.utcnow() + timedelta(hours=8)
    thisdate = "{}/{}".format(thisdate.month, thisdate.day)

    return render_template("frontend/calendar.html", **locals())