Giter VIP home page Giter VIP logo

dchrostowski / investopedia_simulator_api Goto Github PK

View Code? Open in Web Editor NEW
33.0 1.0 11.0 225 KB

A simple Python API for Investopedia's stock simulator games. This programmatically logs into Investopedia and can retrieve portfolio summary, get stock quotes & option chain lookups, execute trades - buy & sell shares, puts, calls, sell short, etc.

License: MIT License

Python 95.07% JavaScript 4.93%
stock-market investment-portfolio stock-trading python3 python api-wrapper api options-trading

investopedia_simulator_api's Introduction

Description

A simple Python API for Investopedia's stock simulator games.

Features

Currently you can programmatically:

  • Read all positions in your stock, and short portfolios and get quotes for each position
  • Fetch and cancel pending/open trades
  • Buy/Sell long positions
  • Short sell/cover short positions
  • Buy/sell options
  • Perform option chain lookups
  • Buy/sell options

Dependencies

To use this API, there are a few dependencies that you will need to install. See the below sections for an explanation of each.

Python

This API is intended to be used for writing Python programs to automate trades in the Investopedia Stock Simulator, therefore you should have Python installed on your system. I recommend using Python 3.12.2 or later to avoid running into issues or other problems. You can download Python here.

Git (optional)

This API is not currently hosted as a package anywhere, so you'll need to download the code directly from GitHub to use it. Download and install the latest version of Git on your system and run the following in a terminal to download a copy of this repository:

git clone https://github.com/dchrostowski/investopedia_simulator_api.git/

Alternatively, you can just download a zipped archive of the source code directly from this project's GitHub page and unzip it somewhere on your filesystem. To do this, click on the green Code button and select Download ZIP.

Node.js

Node.js is utilized to facilitate logging in to the simulator with a virtual web browser and fetching authentication tokens. Download and install the latest version of Node.js on your system here..

Usage

Once all dependencies are installed, you will need to use pip to install supplementary Python packages to run your code with the API. Open a terminal on your system and navigate to where you downloaded this code:

cd path/to/investopedia_simulator_api

Next run the following command to install the supplementary packages:

pip install -r ./requirements.txt

Once all the required packages are installed, you will need to provide your login credentials for the Investopedia Stock Simulator. Rename the credentials_example.json file to credentials.json, open it, and replace the username and password values with your actual username and password for logging in to Investopedia. Make sure you leave the double quotes intaact.

Finally, try running the provided example.py file. This example.py file is a usage example of the API. Feel free to modify it as you see fit for your needs:

python example.py

Example

code

from investopedia_api import InvestopediaApi
import json
from datetime import datetime, timedelta
from api_models import OptionScope
from trade_common import OrderLimit, TransactionType, Expiration, StockTrade, OptionTrade

credentials = {}
with open('credentials.json') as ifh:
    credentials = json.load(ifh)
# look at credentials_example.json
# credentials = {"username": "[email protected]", "password": "yourpassword" }
client = InvestopediaApi(credentials)

p = client.portfolio
print("\nPortfolio Details")
print("-------------------------------------------------")
print("Portfolio Value: %s" % p.account_value)
print("Cash: %s" % p.cash)
print("Buying Power: %s" % p.buying_power)
print("Annual Return Percent: %s" % p.annual_return_pct)
print("-------------------------------------------------")

print("\nOpen Orders:")
# To cancel a pending trade, run open_order.cancel()
for open_order in p.open_orders:
    print("-------------------------------------------------")
    print("Trade Type: %s" % open_order.trade_type)
    print("Symbol: %s" % open_order.symbol)
    print("Quantity: %s" % open_order.quantity)
    print("Price: %s" % open_order.order_price)
    print("-------------------------------------------------")
print("-------------------------------------------------")


stock_portfolio = p.stock_portfolio
short_portfolio = p.short_portfolio
option_portfolio = p.option_portfolio

print("\nStock Portfolio Details:")
print("-------------------------------------------------")
print("Market Value: %s" % p.stock_portfolio.market_value)
print("Today's Gain: %s (%s%%)" % (p.stock_portfolio.day_gain_dollar, p.stock_portfolio.day_gain_percent))
print("Total Gain: %s (%s%%)" % (p.stock_portfolio.total_gain_dollar, p.stock_portfolio.total_gain_percent))
print("-------------------------------------------------")

print("\nLong Positions:")
for position in p.stock_portfolio:
    print("-------------------------------------------------")
    print("Company: %s (%s)" % (position.description, position.symbol))
    print("Shares: %s" % position.quantity)
    print("Purchase Price: %s" % position.purchase_price)
    print("Current Price: %s" % position.current_price)
    print("Today's Gain: %s (%s%%)" % (position.day_gain_dollar, position.day_gain_percent))
    print("Total Gain: %s (%s%%)" % (position.total_gain_dollar, position.total_gain_percent))
    print("Market/Total Value: %s" % position.market_value)
    print("\t------------------------------")
    print("\tQuote")
    print("\t------------------------------")
    quote = position.quote
    for k,v in quote.__dict__.items():
        print("\t%s: %s" % (k,v))
    print("\t------------------------------")
    print("-------------------------------------------------")


print("\nShort Positions:")
for position in p.short_portfolio:
    print("-------------------------------------------------")
    print("Company: %s (%s)" % (position.description, position.symbol))
    print("Shares: %s" % position.quantity)
    print("Purchase Price: %s" % position.purchase_price)
    print("Current Price: %s" % position.current_price)
    print("Today's Gain: %s (%s%%)" % (position.day_gain_dollar, position.day_gain_percent))
    print("Total Gain: %s (%s%%)" % (position.total_gain_dollar, position.total_gain_percent))
    print("Market/Total Value: %s" % position.market_value)
    print("\t------------------------------")
    print("\tQuote")
    print("\t------------------------------")
    quote = position.quote
    for k,v in quote.__dict__.items():
        print("\t%s: %s" % (k,v))
    print("\t------------------------------")
    print("-------------------------------------------------")

print("\nOption Positions:")
for position in p.option_portfolio:
    print("-------------------------------------------------")
    print("Company: %s (%s)" % (position.description, position.underlying_symbol))
    print("Symbol: %s" % position.symbol)
    print("Contracts: %s" % position.quantity)
    print("Purchase Price: %s" % position.purchase_price)
    print("Current Price: %s" % position.current_price)
    print("Today's Gain: %s (%s%%)" % (position.day_gain_dollar, position.day_gain_percent))
    print("Total Gain: %s (%s%%)" % (position.total_gain_dollar, position.total_gain_percent))
    print("Market/Total Value: %s" % position.market_value)
    print("\t------------------------------")
    print("\tQuote")
    print("\t------------------------------")
    quote = position.quote
    for k,v in quote.__dict__.items():
        print("\t%s: %s" % (k,v))
    print("\t------------------------------")
    print("-------------------------------------------------")

# Make a stock trade
    
# Buy 2 shares of GOOG with limit $100 and no expiration
tt1 = TransactionType.BUY
ol1 = OrderLimit.LIMIT(100)
exp1 = Expiration.GOOD_UNTIL_CANCELLED()
trade1 = StockTrade(portfolio_id=p.portfolio_id, symbol="GOOG", quantity=2, transaction_type=tt1, order_limit=ol1, expiration=exp1)
trade1.validate()
trade1.execute()

# Buy 3 shares of AAPL at market value with expiration set to end of day
# defaults order_limit to OrderLimit.MARKET() and expiration to Expiration.END_OF_DAY())
trade2 = StockTrade(portfolio_id=p.portfolio_id, symbol='AAPL', quantity=3, transaction_type=TransactionType.BUY)
trade2.validate()
trade2.execute()

# short sell 1 share of AMZN
trade3 = StockTrade(portfolio_id=p.portfolio_id, symbol='AMZN', quantity=1, transaction_type=TransactionType.SELL_SHORT)
trade3.validate()
trade3.execute()


client.refresh_portfolio()
p = client.portfolio

for open_order in p.open_orders:
    if open_order.symbol == 'GOOG' and open_order.quantity == 2:
        # cancel GOOG trade
        open_order.cancel()
    
    if open_order.symbol == 'AAPL' and open_order.quantity == 3:
        # cancel AAPL trade
        open_order.cancel()

    if open_order.symbol == 'AMZN' and open_order.quantity == 1:
        # cancel AMZN trade
        open_order.cancel()


stock_portfolio = p.stock_portfolio
if len(p.stock_portfolio) > 0:
    # first long position in portfolio
    first_long_position = p.stock_portfolio[0]
    symbol = first_long_position.symbol
    quantity = first_long_position.quantity
    
    # execute trade to sell position in portfolio
    first_long_position.sell()
    client.refresh_portfolio()
    p = client.portfolio
    for oo in p.open_orders:
        if oo.symbol == symbol and oo.quantity == quantity:
            # cancel trade to sell first position in portfolio
            oo.cancel()

short_portfolio = p.short_portfolio
if len(p.short_portfolio) > 0:
    # first short position in portfolio
    first_short_position = p.short_portfolio[0]
    symbol = first_short_position.symbol
    quantity = first_short_position.quantity
    
    # execute trade to cover position in portfolio
    first_short_position.cover()
    client.refresh_portfolio()
    p = client.portfolio
    for oo in p.open_orders:
        # cancel cover trade you just made
        if oo.symbol == symbol and oo.quantity == quantity:
            # cancel trade to cover first position in portfolio
            oo.cancel()

if len(p.option_portfolio) > 0:
    first_option_contract = p.option_portfolio[0]
    symbol = first_option_contract.symbol
    quantity = first_option_contract.quantity
    # close out first option contract in portfolio
    first_option_contract.close()
    client.refresh_portfolio()
    p = client.portfolio
    for oo in p.open_orders:
        # cancel order to close out contract
        if oo.symbol == symbol and oo.quantity == quantity:
            oo.cancel()


# Gets all available option contracts for AAPL
oc = client.get_option_chain('AAPL')
all_options = oc.all()
print("There are %s available option contracts for AAPL" % len(all_options))


two_weeks_from_today = datetime.now() + timedelta(days=14)
print("AAPL in-the-money put options expiring within two weeks:")
put_options_near_expiration_itm = oc.search(before=two_weeks_from_today, puts=True, calls=False, scope=OptionScope.IN_THE_MONEY)
for option in put_options_near_expiration_itm:
    print("%s:\n\tbid: %s\n\task: %s\n\tlast price: %s\n\texpires:%s" % (option.symbol, option.bid, option.ask, option.last, option.expiration.strftime("%m/%d/%Y") ))


option_to_buy = put_options_near_expiration_itm[0]
trade4 = OptionTrade(portfolio_id=p.portfolio_id, symbol=option_to_buy.symbol, quantity=1, transaction_type=TransactionType.BUY)
trade4.validate()
trade4.execute()
client.refresh_portfolio()

p = client.portfolio
for oo in p.open_orders:
    if oo.symbol == option_to_buy.symbol:
        oo.cancel()

    ```

investopedia_simulator_api's People

Contributors

binarynightowl avatar dchrostowski avatar dchrostowski1 avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

investopedia_simulator_api's Issues

Get Investopedia Login Cookie

Hello,
For the last while or so I have been trying to figure out how to get the login cookie from the investopedia login with no success. Any idea on how I can do so?
Thanks

Stock quote limit?

Is there a way to get around the 10 stock quote limit? Like if I want to get quotes on 100 stocks.

Cancelling an order

Is there any way to cancel an order through this api once it has been placed? For example, because of the delay on orders going through, some of them I may want to cancel because the price is too high

Cannot login?

Reproduce:
insert valid credentials into the dictionary and see this error:

TimeoutError: Waiting for selector `::-p-xpath(//span[contains(text(),"LOG IN")])` failed: Waiting failed: 3000ms exceeded
    at new WaitTask (file:///F:/Progetti/Python/SeleniumStock/node_modules/puppeteer-core/lib/esm/puppeteer/common/WaitTask.js:47:34)
    at IsolatedWorld.waitForFunction (file:///F:/Progetti/Python/SeleniumStock/node_modules/puppeteer-core/lib/esm/puppeteer/api/Realm.js:22:26)
    at PQueryHandler.waitFor (file:///F:/Progetti/Python/SeleniumStock/node_modules/puppeteer-core/lib/esm/puppeteer/common/QueryHandler.js:167:95)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async CdpFrame.waitForSelector (file:///F:/Progetti/Python/SeleniumStock/node_modules/puppeteer-core/lib/esm/puppeteer/api/Frame.js:466:21)
    at async CdpPage.waitForSelector (file:///F:/Progetti/Python/SeleniumStock/node_modules/puppeteer-core/lib/esm/puppeteer/api/Page.js:1287:20)
    at async file:///F:/Progetti/Python/SeleniumStock/auth.js:46:29
Traceback (most recent call last):
  File "F:\Progetti\Python\SeleniumStock\example.py", line 8, in <module>
    client = InvestopediaApi(credentials)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "F:\Progetti\Python\SeleniumStock\investopedia_api.py", line 10, in __init__
    Session.login(credentials)
  File "F:\Progetti\Python\SeleniumStock\session_singleton.py", line 97, in login
    raise InvestopediaAuthException("Unable to login with credentials '%s', '%s'" % (credentials['username'],credentials['password']))
session_singleton.InvestopediaAuthException: Unable to login with credentials '--------', '-------------'

Investopedia site change

Just wanted to give you a heads up that Investopedia changed their simulator page. For sure the login does not work, and possible many of the other calls will fail as well.

How to fix 'open_orders' method

  1. Line 42 in file "utils.py"
    INCORRECT : hour = int(date_ints[3])
    CORRECT : hour = int(date_ints[3]) % 12

  2. Line 201 in file "parsers.py"
    INCORRECT : if open_order_dict['order_price'] = 'n/a' :
    CORRECT : if open_order_dict['order_price'] != 'n/a' :

best regards.

Get more info

I am looking at getting some more info for when I pull stock requests: specifically intraday Open, High, and Low price

In parsers.py I was able to find where you have some of the info: Line 110

xpath_map = {
    'name': '//h3[@class="companyname"]/text()',
    'symbol': '//table[contains(@class,"table3")]/tbody/tr[1]/td[1]/h3[contains(@class,"pill")]/text()',
    'exchange': '//table[contains(@class,"table3")]//div[@class="marketname"]/text()',
    'last': '//table[@id="Table2"]/tbody/tr[1]/th[contains(text(),"Last")]/following-sibling::td/text()',
    'change': '//table[@id="Table2"]/tbody/tr[2]/th[contains(text(),"Change")]/following-sibling::td/text()',
    'change_percent': '//table[@id="Table2"]/tbody/tr[3]/th[contains(text(),"% Change")]/following-sibling::td/text()',
    'volume': '//table[@id="Table2"]/tbody/tr[4]/th[contains(text(),"Volume")]/following-sibling::td/text()'
}

I was just wondering where you pull this information from so I could add my own hopefully. I also see that I will need to update api_models.py:

class StockQuote(object):
@coerce_method_params
def init(
self: object,
symbol: str,
name: str,
exchange: str,
last: Decimal,
change: Decimal,
change_percent: Decimal,
volume: int

):
    self.symbol = symbol
    self.name = name
    self.last = last
    self.exchange = exchange
    self.change = change
    self.change_percent = change_percent
    self.volume = volume

Correct me if I'm wrong? Would there be anything else I would have to update?

KeyError: 'account_cookie'

image
Ok so I'm pretty close to getting your API to work, but as on now my API key (or I suppose it is more of a cookie) does not seem to be working. I got it from the UL4 cookie in FireFox after logging in and i put it into the auth_cookie.json with proper formatting (i just followed what the example one said to do) and I seem to be getting a KeyError (see screenshot attatched for refrence) any idea as to what might be going on?

Add documentation

Documentation Needed

General

  • InvestopediaApi
  • StockQuote

Trading

  • Trade
  • StockTrade
  • OptionTrade
  • TradeType
  • OrderType
  • Duration
  • TradeExceedsMaxSharesException

Portfolio

  • Portfolio
  • StockPortfolio
  • OptionPortfolio
  • ShortPortfolio
  • Position
  • StockPosition
  • OptionPosition
  • ShortPosition
  • StockQuote

Options

  • OptionChainLookup
  • OptionChain
  • OptionContract

Refactor Portfolio class

------------------------------
Portfolio(list)
------------------------------
account_value: Decimal
buying_power: Decimal
cash: Decimal
annual_return_pct: Decimal
stock_portfolio: StockPortfolio
option_portfolio: OptionPortfolio
shorted_portfolio: ShortedPortfolio
------------------------------
reload() -> None
------------------------------
------------------------------
**StockPortfolio(Portfolio)**
------------------------------
positions: LongPosition[]
------------------------------
total_value() -> Decimal
total_change() -> Decimal
------------------------------
------------------------------
**ShortedPortfolio(Portfolio)**
------------------------------
positions: ShortPosition[]
------------------------------
total_value() -> Decimal
total_change() -> Decimal
------------------------------
------------------------------
**OptionPortfolio(Portfolio)**
------------------------------
positions: OptionPosition[]
------------------------------
total_value() -> Decimal
total_change() -> Decimal
------------------------------

Refactor Position class

class Position(object):
    @correct_method_params
    def __init__(
      self: object, 
      portfolio_id: str, 
      symbol: str, 
      quantity: int, 
      description:str, 
      purchase_price: Decimal, 
      current_price: Decimal, 
      total_value: Decimal):

        self.portfolio_id = portfolio_id
        self.symbol = symbol
        self.quantity = quantity
        self.description = description
        self.purchase_price = purchase_price
        self.current_price = current_price
        self.total_value = total_value

    @classmethod
    def from_tr_element(cls, tr):
        pass


class LongPosition(Position):
    stock_type_assertion = 'long'

    def __init__(self, trade_link, stock_type, **kwargs):
        super().__init__(**kwargs)
        assert stock_type == self.stock_type_assertion
        self.stock_type = stock_type
        self.trade_link = trade_link

    @correct_method_params
    def foo(self,a,b):
        print(a)


class ShortPosition(Position):
    stock_type_assertion = 'short'

    def __init__(self, trade_link, stock_type, **kwargs):
        super().__init__(**kwargs)
        assert stock_type == self.stock_type_assertion
        self.stock_type = stock_type
        self.trade_link = trade_link


class OptionPosition(Position):
    stock_type_assertion = 'long'

    def __init__(self, trade_link, stock_type, **kwargs):
        super().__init__(**kwargs)
        assert stock_type == self.stock_type_assertion
        self.stock_type = stock_type
        self.trade_link = trade_link

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.