def predict_price_change():
    '''Train model and predict probability of price change in the next day for each symbol.
       If run on the non-trading day, e.g. weekends, the current probabilities are updated
    '''
    logger.info('Called')

    symbols = db_init['symbols']
    line = get_last_line(_prob_pred_file).split(',')

    # If on the non-trading day, update the probability predictions
    if line[0] == 'NA':
        logger.info('Update the current predicted probabilities')
        pop_last_line(_prob_pred_file)

    prob_pred = {}

    for symbol in symbols:
        model = Model(symbol)
        model.load_data()
        model.fit()

        neg, neu, pos = model.predict_proba()
        prob_pred[symbol] = tuple(map(lambda x: round(x, 4), (neg, neu, pos)))

    # Log probability predictions for the next trading day
    prob = ['NA'] + [v for symbol in symbols for v in prob_pred[symbol]]

    with open(_prob_pred_file, 'a') as f:
        f.write(','.join(map(str, prob)) + '\n')
def get_curr_holding():
    '''Get current holding'''

    symbols = db_init['symbols']

    line = get_last_line(_portfolio_file).split(',')
    share = {s: int(v) for s, v in zip(symbols, line[1:-3:3])}
    cash, total_value = float(line[-3]), float(line[-2])

    return line[0], share, cash, total_value
Exemple #3
0
def update_ta_feature(symbol: str):
    '''Update ta features for the specified symbol with the latest daily time series data'''
    logger.info('Called for %s', symbol)

    db = db_init['db']

    last_trade_day = Database.get_last_trade_day(db, symbol)
    last_ta_line = get_last_line(_data_folder + '{0}_ta.csv'.format(symbol))
    last_ta_day = last_ta_line.split(',')[0]

    logger.info('Last trade day: %s, last ta day: %s', last_trade_day, last_ta_day)

    if last_ta_day < last_trade_day:
        data = Database.get_data_daily(db, symbol, start=_since_this_date)
        build_ta_feature(symbol, data)
Exemple #4
0
def update_news_feature(symbol: str):
    '''Update mews features for the specified symbol with the latest news data.
       Should be used on a daily basis
    '''
    logger.info('Called for %s', symbol)

    db, symbols = db_init['db'], db_init['symbols']

    if symbol == 'Market':
        last_trade_day = Database.get_last_trade_day(db, symbols[0])
    else:
        last_trade_day = Database.get_last_trade_day(db, symbol)
    
    # Get news data and build feature for the last trade day
    news = Database.get_data_news(db, symbol, start=last_trade_day)
    news_feature = build_news_feature(last_trade_day, news)

    from_date, to_date = (news[0][0], news[-1][0]) if len(news) > 0 else ('-', '-')
    logger.info('Get %d news, from %s to %s', len(news), from_date, to_date)

    # Get the date for the last news feature in file to determine whether the
    # newly built news feature should override the existing one or simply append
    new_feature_file = _data_folder + '{0}_news.csv'.format(symbol)
    last_news_line = get_last_line(new_feature_file)
    last_news_day = last_news_line.split(',')[0]

    logger.info('Last trade day: %s, last news day: %s', last_trade_day, last_news_day)
    if last_news_day > last_trade_day:
        logger.error('Unexpected behavior for last trade and news date')

    if last_news_day == last_trade_day:
        logger.info('Override the news feature for %s', last_news_day)
        pop_last_line(new_feature_file)
    else:
        logger.info('Add the news feature for %s', last_trade_day)

    with open(new_feature_file, 'a') as f:
        f.write(','.join(map(str, news_feature)) + '\n')
    log_info("Retrieving the price data (country code: %s)" % cc)

    rest_apps = list(apps)
    while len(rest_apps) != 0:

        log_info("There are %d apps left" % len(rest_apps))

        # Retrieve the first {APPS_PER_REQUEST} apps
        this_time_apps = []
        next_time_apps = []
        for (app_id, app_name) in rest_apps:
            if len(this_time_apps) < APPS_PER_REQUEST:
                # Check if we have the price data for this app today
                file_path = cc_dir + "/app_price_" + str(app_id) + ".txt"
                if os.path.exists(file_path):
                    last_line = get_last_line(file_path)
                    time_str = last_line.split(' ')[0]

                    if time_to_day(int(time_str)) == time_to_day(START_TIME):
                        continue

                this_time_apps.append((app_id, app_name))

            else:
                next_time_apps.append((app_id, app_name))
        rest_apps = next_time_apps

        # Retrieve the price of the first 100 apps
        url = APP_URL_PREFIX
        for (app_id, _) in this_time_apps:
            url += str(app_id) + ','
def finalize_transaction():
    '''Finalized the transaction for today based on the predicted probabilities and
       update the fund using the lastest daily price data.

       Rule to follow:
           If today is a trading day, then buy shares at the open price, based on 
           the predicted probabilities and the derived trading strategy. The total 
           value at the end of day is calculated with the close price. 

           If not a trading day, do nothing.
    '''
    logger.info('Called')

    db, symbols = db_init['db'], db_init['symbols']

    # Probabilities of price change for this day
    curr_prob = pop_last_line(_prob_pred_file).split(',')
    if curr_prob[0] != 'NA':
        logger.error('Probability data not available: %s', curr_prob[0])

    last_transaction = get_last_line(_portfolio_file).split(',')
    cash = float(last_transaction[-3])
    last_trade_day = Database.get_last_trade_day(db, symbols[0])

    logger.info('Last trade day: %s', last_trade_day)
    logger.info('Last transaction date: %s', last_transaction[0])
    if last_trade_day < last_transaction[0]:
        logger.error('Unexpected behavior for last trade and transaction date')

    # New daily price data is available to finalize the transaction
    if last_trade_day > last_transaction[0] and curr_prob[0] == 'NA':
        logger.info('Finalize transaction for: %s', last_trade_day)

        init_share, init_cash, _ = get_init_holding()
        curr_share = {
            s: int(v)
            for s, v in zip(symbols, last_transaction[1:-3:3])
        }
        probs = {
            s: tuple(map(float, curr_prob[i * 3 + 1:i * 3 + 4]))
            for i, s in enumerate(symbols)
        }

        curr_open, curr_close = {}, {}

        # Get open and close price for this day
        for symbol in symbols:
            data = Database.get_data_daily(db=db,
                                           symbol=symbol,
                                           start=last_trade_day)[0]
            curr_open[symbol], curr_close[symbol] = float(data[1]), float(
                data[4])

        # Buy/sell shares at the open price
        for symbol in symbols:
            # A simple strategy
            pos, neg = probs[symbol][-1], probs[symbol][0]
            transaction = int(round(init_share[symbol] * (pos - neg) / 2, 0))

            # Do not consider short-selling
            if curr_share[symbol] + transaction < 0:
                transaction = -curr_share[symbol]

            logger.info('Trading decision for %s (%d): %d share (%.4f, %.4f)',
                        symbol, curr_share[symbol], transaction, pos, neg)

            # Log this transaction to trade history
            with open(_trade_history_file, 'a') as f:
                record = (last_trade_day, symbol, curr_share[symbol],
                          transaction, round(curr_open[symbol], 4))
                f.write(','.join(map(str, record)) + '\n')

            # Update number of shares and cash
            curr_share[symbol] += transaction
            cash -= transaction * curr_open[symbol]

        # Total value and benchmark at the end of day
        total = cash + sum(curr_share[symbol] * curr_close[symbol]
                           for symbol in symbols)
        benchmark = init_cash + sum(init_share[symbol] * curr_close[symbol]
                                    for symbol in symbols)

        # Update the transaction information
        curr_transaction = [last_trade_day]
        for symbol in symbols:
            curr_transaction += [
                curr_share[symbol], curr_open[symbol], curr_close[symbol]
            ]
        curr_transaction += [
            round(cash, 4),
            round(total, 4),
            round(benchmark, 4)
        ]

        with open(_portfolio_file, 'a') as f:
            f.write(','.join(map(str, curr_transaction)) + '\n')

        # Update the date for the probability predictions made for this day
        curr_prob[0] = last_trade_day

        _validate_cash()

    with open(_prob_pred_file, 'a') as f:
        f.write(','.join(curr_prob) + '\n')