Пример #1
0
def handle_add_to_watchlist(request):
    """
    Generate response to intent type AddStockToWatchlistIntent based on the stage of the adding stock to portfolio process.
    :type request AlexaRequest
    :return: JSON response including appropriate response based on the stage in the adding process.
    """

    if request.dialog_state() == "STARTED":
        return _handle_dialog_add_started(request)
    elif request.dialog_state() == "IN_PROGRESS":
        return _handle_dialog_add_in_progress(request)
    elif request.dialog_state() == "COMPLETED":
        # TODO
        return ResponseBuilder.create_response(
            request, "Add to watchlist dialog completed! ")
    elif request.dialog_state() == "":
        # TODO
        print("LOG-d: dialogState not included")
        return ResponseBuilder.create_response(
            request, "Add to watchlist dialog state empty! ")
    else:
        print("LOG-d: dialogState else")
        # TODO
        print("LOG-d: dialogState not included")
        return ResponseBuilder.create_response(
            request, "Add to watchlist dialog state ELSE! ")
Пример #2
0
def _handle_dialog_remove_started(request):
    """
    Check if the provided ticker is valid and stock is in watchlist, if yes, ask for confirmation. Otherwise, inform about the state.
    :type request AlexaRequest
    """
    logger.debug("dialogState STARTED")
    user_id = request.user_id()

    # Check if ticker is provided
    try:
        ticker = _check_valid_ticker_provided(request)
    except AttributeError as e:
        logger.exception("No valid ticker provided")
        message = strings.INTENT_REMOVE_FROM_WATCHLIST_FAIL
        return ResponseBuilder.create_response(request, message=message) \
            .with_reprompt(strings.INTENT_GENERAL_REPROMPT)

    # Check if stock is in users Watchlist
    is_in_watchlist = Watchlist.ticker_in_watchlist_exists(user_id, ticker)

    # Inform that stock not in watchlist, or ask user to confirm ticker remove
    if is_in_watchlist:
        logger.debug(
            f"Ask confirmation: remove stock {ticker} from user:{user_id} watchlist"
        )
        message = strings.INTENT_REMOVE_FROM_WATCHLIST_ASK_CONFIRMATION \
            .format(ticker)
        return ResponseBuilder.create_response(request, message) \
            .with_dialog_confirm_intent()
    else:
        logger.debug(
            f"Trying to remove stock {ticker}, which is not in wathclist")
        message = strings.INTENT_REMOVE_FROM_WATCHLIST_NOT_THERE.format(ticker)
        return ResponseBuilder.create_response(request, message)
Пример #3
0
def _handle_dialog_add_started(request):
    """
    Check if the provided ticker is supported or is not already in watchlist, if not, ask for confirmation.
    :type request AlexaRequest
    """
    print("LOG-d: dialogState STARTED")

    # Check if ticker is provided
    try:
        ticker = _check_valid_ticker_provided(request)
    except AttributeError as e:
        logger.exception("No valid ticker provided")
        message = strings.INTENT_ADDED_TO_WATCHLIST_FAIL
        return ResponseBuilder.create_response(request, message=message) \
            .with_reprompt(strings.INTENT_GENERAL_REPROMPT)

    # Ask user to confirm ticker add
    message = strings.INTENT_ADD_TO_WATCHLIST_ASK_CONFIRMATION.format(ticker)

    # Check if ticker not already in Watchlist
    user_id = request.get_user_id()
    watchlist_tickers = Watchlist.get_users_tickers(user_id)
    for ticker_in_watchlist in watchlist_tickers:
        if ticker == ticker_in_watchlist:
            message = strings.INTENT_ADDED_TO_WATCHLIST_EXISTS.format(ticker)

    return ResponseBuilder.create_response(request, message) \
        .with_dialog_confirm_intent()
Пример #4
0
def handle_market_cap(request):
    """
    Generate response to intent type MarketCapIntent with the current market cap of the ticker.
    :type request AlexaRequest
    :return: JSON response including market cap of the ticker
    """
    ticker = request.get_slot_value(slot_name="stockTicker").upper()

    # Query DB for stock data
    company_stats = Stock.get_stats(ticker)
    market_cap = company_stats.get('marketcap', None)
    company_name = company_stats.get('companyName', ticker)

    if type(market_cap) is NoneType:
        logger.error(f"There was an error getting market capitalization for {company_name}")
        message = strings.INTENT_MARKET_CAP_MSG_FAIL.format(ticker)
        response = ResponseBuilder.create_response(request, message=message)
    else:
        message = strings.INTENT_MARKET_CAP_MSG.format(company_name, market_cap)
        response = ResponseBuilder.create_response(request, message=message) \
            .set_session('stockTicker', ticker)

    reprompt_message = strings.INTENT_GENERAL_REPROMPT

    return response.with_reprompt(reprompt_message)
Пример #5
0
def handle_recommendation(request):
    """
        Generate response to intent type RecommendationIntent with the analytics recommendation for a particular stock.
        :type request AlexaRequest
        :return: JSON response including a recommendation what the analytics think about that stock
    """
    ticker = request.get_slot_value(slot_name="stockTicker").upper()
    recommendation = Analyst(ticker).recommendation()

    logger.info(
        f"recommendationMean for {ticker} is {recommendation}")

    # pick right response based on recommendation mean rating
    if recommendation is None:
        message = strings.INTENT_RCMD_NO_RCMD
    elif _in_interval(recommendation, 1, 1.8):
        message = strings.INTENT_RCMD_STRONG_BUY
    elif _in_interval(recommendation, 1.8, 2.2):
        message = strings.INTENT_RCMD_BUY
    elif _in_interval(recommendation, 2.2, 2.8):
        message = strings.INTENT_RCMD_OPT_HOLD
    elif _in_interval(recommendation, 2.8, 3.2):
        message = strings.INTENT_RCMD_HOLD
    elif _in_interval(recommendation, 3.2, 3.8):
        message = strings.INTENT_RCMD_PES_HOLD
    elif _in_interval(recommendation, 3.8, 4.2):
        message = strings.INTENT_RCMD_SELL
    elif _in_interval(recommendation, 4.2, 5):
        message = strings.INTENT_RCMD_STRONG_SELL

    response = ResponseBuilder.create_response(request, message=message)
    reprompt_message = strings.INTENT_GENERAL_REPROMPT

    return response.with_reprompt(reprompt_message)
Пример #6
0
def handle_not_authenticated(request):
    """ Build a response for case where user has not
    linked the account in Alexa App.
    """
    message = strings.ERROR_NOT_AUTHENTICATED
    reprompt_message = strings.ERROR_NOT_AUTHENTICATED_REPROMPT

    return ResponseBuilder.create_response(request, message=message) \
        .with_reprompt(message=reprompt_message) \
        .with_card("", card_type="LinkAccount")
Пример #7
0
def handle_launch(request):
    """
    Generate response for a launch request like 'Open OttoBot'.
    :param request: incoming parsed Alexa request
    :return: Generated JSON welcome response answer
    """
    message = strings.REQUEST_LAUNCH_MSG
    reprompt_message = strings.REQUEST_LAUNCH_REPROMPT

    return ResponseBuilder.create_response(request, message=message) \
        .with_reprompt(message=reprompt_message)
Пример #8
0
def _handle_dialog_add_in_progress(request):
    """
    Check if the stock adding request was confirmed by the user. If it was, add it to portfolio, otherwise do not add.
    :type request AlexaRequest
    """
    logger.debug("dialogState IN_PROGRESS")

    if request.get_intent_confirmation_status() == "CONFIRMED":
        return _add_ticker_to_watchlist(request)
    else:
        message = strings.INTENT_ADD_TO_WATCHLIST_DENIED
        return ResponseBuilder.create_response(request, message=message)
Пример #9
0
def handle_help_intent(request):
    """
    Generate response to intent type HelpIntent which presents the available futures to the confused user.
    :type request AlexaRequest
    :return: JSON response including introduced capabilities of the skill
    """
    logger.info("Help requested by the user")

    message = strings.INTENT_HELP
    reprompt_message = strings.INTENT_GENERAL_REPROMPT
    return ResponseBuilder.create_response(request, message=message)\
        .with_reprompt(reprompt_message)
Пример #10
0
def _handle_dialog_remove_in_progress(request):
    """
    Check if the stock removing request was confirmed by the user. If it was, remove it from portfolio, otherwise do not.
    :type request AlexaRequest
    """
    logger.debug("dialogState IN_PROGRESS")

    if request.get_intent_confirmation_status() == "CONFIRMED":
        return _remove_ticker_from_watchlist(request)
    else:
        logger.debug(f"Deny deleting of stock from watchlist")
        message = strings.INTENT_REMOVE_FROM_WATCHLIST_DENIED
        return ResponseBuilder.create_response(request, message=message)
Пример #11
0
def handle_get_stock_price_intent(request):
    """
    Generate response to intent type WhatsTheStockPriceIntent with the current price of the added ticker.
    :type request AlexaRequest
    :return: JSON response including stock price
    """
    ticker = request.get_slot_value(slot_name="stockTicker").upper()

    # Query DB for stock data
    stock = Stock.get_last(ticker)

    if type(stock) is NoneType:
        logger.error(f"There was an error getting data for {ticker}")
        message = strings.INTENT_STOCK_PRICE_MSG_FAIL.format(ticker)
        response = ResponseBuilder.create_response(request, message=message)
    else:
        message = strings.INTENT_STOCK_PRICE_MSG.format(stock['ticker'], stock['price'])
        response = ResponseBuilder.create_response(request, message=message) \
            .set_session('stockTicker', stock['ticker'])

    reprompt_message = strings.INTENT_GENERAL_REPROMPT

    return response.with_reprompt(reprompt_message)
Пример #12
0
def _handle_dialog_send_article(request):
    """Create a response with card containing requested article."""
    reprompt = strings.INTENT_GENERAL_REPROMPT

    ticker = request.get_slot_value('stockTicker')
    company = Ticker2Name.ticker_to_name(ticker)
    article_no = int(request.get_slot_value('articleNo')) - 1
    # last news
    if article_no == -1:
        article_no = news_count - 1

    feed_reader = FeedReader(ticker)
    article_title = feed_reader.get_articles_titles()[article_no]
    article_body = feed_reader.get_article_body(article_no)
    if article_body is None:
        # Article not found
        message = strings.INTENT_NEWS_ABOUT_COMPANY_FAIL_ARTICLE_NOT_FOUND
        return ResponseBuilder.create_response(request, message=message) \
            .with_reprompt(reprompt)

    # Build response
    message = strings.INTENT_NEWS_ABOUT_COMPANY_ARTICLE_SENT
    card_title = strings.INTENT_NEWS_ABOUT_COMPANY_ARTICLE_CARD_TITLE \
        .format(company)
    card_content = strings.INTENT_NEWS_ABOUT_COMPANY_ARTICLE_CARD_CONTENT \
        .format(article_body)

    send_as_card = True
    if send_as_card:
        return ResponseBuilder.create_response(request, message=message) \
            .with_reprompt(reprompt) \
            .with_card(card_title, content=card_content, subtitle=article_title)
    else:
        # Present article as speech
        return ResponseBuilder.create_response(request, message=card_content) \
            .with_reprompt(reprompt)
Пример #13
0
def handle_investing_strategy(request):
    """
    Generate response to intent type InvestingStrategyIntent with explanation of a random investing strategy.
    :type request AlexaRequest
    :return: JSON response including investing strategy name and explanation
    """
    strategies = strings_edu.STRATEGIES['data']
    pick = random.randint(0, len(strategies) - 1)

    strategy_name = strategies[pick]['name']
    strategy_content = strategies[pick]['content']

    message = strings.INTENT_INVEST_STRAT_MSG.format(strategy_name,
                                                     strategy_content)
    reprompt_message = strings.INTENT_GENERAL_REPROMPT

    return ResponseBuilder.create_response(request, message=message) \
        .with_reprompt(reprompt_message)
Пример #14
0
def handle_news(request):
    """
    Generate response to intent type NewsAboutCompanyIntent based on the stage of the dialog.
    :type request AlexaRequest
    :return: JSON response including appropriate response based on the stage of the dialog.
    """
    if request.dialog_state() == "STARTED":
        return _handle_dialog_read_titles(request)
    if request.dialog_state() == "IN_PROGRESS":
        if request.get_slot_value('articleNo') is None:
            if request.get_intent_confirmation_status() == "CONFIRMED":
                # Ask user which article he wants details about
                return _handle_dialog_which_one(request)
            else:
                # User doesn't want more info
                message = strings.INTENT_GENERAL_OK
                return ResponseBuilder.create_response(request,
                                                       message=message)
        else:
            # Send user full article in a card
            return _handle_dialog_send_article(request)
Пример #15
0
def _add_ticker_to_watchlist(request):
    """
    Add ticker to users Watchlist and build response.
    :type request AlexaRequest
    """
    user_id = request.get_user_id()
    ticker = request.get_slot_value('stockTicker')
    if ticker is None:
        ticker = request.get_session_attribute('stockTicker')

    message = strings.INTENT_ADD_TO_WATCHLIST_CONFIRMED.format(ticker)
    reprompt_message = strings.INTENT_GENERAL_REPROMPT

    # Save stock to watchlist
    try:
        user_id = request.get_user_id()
        Watchlist(ticker, user_id).save()
    except EntryExistsError as e:
        message = strings.ERROR_CANT_ADD_TO_WATCHLIST.format(ticker)

    return ResponseBuilder.create_response(request, message=message) \
        .with_reprompt(reprompt_message)
Пример #16
0
def handle_report_stock_watchlist(request):
    """
    Generate response to intent type ReportStockWatchlistIntent reporting the current portfolio performance.
    :type request AlexaRequest
    :return: JSON response including the performance report.
    """
    user_id = request.get_user_id()

    # Query DB for watchlist data
    ticker_list = Watchlist.get_users_tickers(user_id)
    changes = _get_stocks_24h_change(ticker_list)

    if len(ticker_list) > 2:
        max_idx = _find_biggest_value(changes)
        gainer_ticker = ticker_list.pop(max_idx)
        gainer_value = changes.pop(max_idx)
        min_idx = _find_smallest_value(changes)
        loser_ticker = ticker_list.pop(min_idx)
        loser_value = changes.pop(min_idx)

        gainer_message = strings.INTENT_WATCHLIST_REPORT_TOP_STOCK.format(
            Ticker2Name.ticker_to_name(gainer_ticker),
            _get_movement_direction(gainer_value),
            abs(gainer_value))
        loser_message = strings.INTENT_WATCHLIST_REPORT_WORST_STOCK.format(
            Ticker2Name.ticker_to_name(loser_ticker),
            _get_movement_direction(loser_value),
            abs(loser_value))

        message = gainer_message + loser_message + _build_report_msg(ticker_list, changes)
    elif len(ticker_list) == 2 or len(ticker_list) == 1:
        message = _build_report_msg(ticker_list, changes)
    else:
        message = strings.INTENT_WATCHLIST_EMPTY_MSG

    reprompt_message = strings.INTENT_GENERAL_REPROMPT
    return ResponseBuilder.create_response(request, message=message) \
        .with_reprompt(reprompt_message)
Пример #17
0
def _remove_ticker_from_watchlist(request):
    """
    Remove ticker from users Watchlist if there and build response.
    :type request AlexaRequest
    """
    user_id = request.get_user_id()
    ticker = request.get_slot_value('stockTicker')
    if ticker == "NONE":
        ticker = request.get_session_attribute('stockTicker')

    message = strings.INTENT_REMOVE_FROM_WATCHLIST_CONFIRMED.format(ticker)
    reprompt_message = strings.INTENT_GENERAL_REPROMPT

    # Delete stock from watchlist
    try:
        Watchlist(ticker, user_id).delete()
    except EntryExistsError as e:
        logger.exception(
            f"Error while deleting ticker {ticker} from Watchlist")

    logger.debug(f"Deleted stock {ticker} from user:{user_id} watchlist")
    return ResponseBuilder.create_response(request, message=message) \
        .with_reprompt(reprompt_message)
Пример #18
0
def _handle_dialog_which_one(request):
    """Create a response asking which article user wants to know about to get articleNo."""
    message = strings.INTENT_NEWS_ABOUT_COMPANY_ASK_ARTICLE_NO
    return ResponseBuilder.create_response(request, message=message) \
        .with_dialog_elicit_slot()