Generating API keys for Polymarket.com

Here is a quick tutorial on how to generate API Key, Secret, and Passphrase to Polymarket.com. This way you can start trading using Python and skip the web interface.

keys.env

The first step is to create an environment file. You only want to populate the PK value. You do not know the other 3 variables yet so just comment them out. You can find this private key by logging in to your Polymarket.com account. Clicking on ‘Cash’, 3 dots, and finally Export Private Key.

#remove the '0x'
PK = "PRIVATE KEY EXPORTED FROM POLYMARKET.COM"

#these are generated through get_api_key.py do not specify these until you run the script with your private key
#API Key: xxxxxxxx-xxxx-xxxxx-xxxx-xxxxxxxxxxxx
#Secret: Lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
#Passphrase: dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe9

generate_api_key.py

import os
from py_clob_client.client import ClobClient
from dotenv import load_dotenv

# Load the environment variables from the specified .env file
load_dotenv('keys.env')

def main():
    host = "https://clob.polymarket.com"
    key = os.getenv("PK")
    chain_id = 137  # Polygon Mainnet chain ID

    # Ensure the private key is loaded correctly
    if not key:
        raise ValueError("Private key not found. Please set PK in the environment variables.")

    # Initialize the client with your private key
    client = ClobClient(host, key=key, chain_id=chain_id)

    # Create or derive API credentials (this is where the API key, secret, and passphrase are generated)
    try:
        api_creds = client.create_or_derive_api_creds()
        print("API Key:", api_creds.api_key)
        print("Secret:", api_creds.api_secret)
        print("Passphrase:", api_creds.api_passphrase)

        # You should now save these securely (e.g., store them in your .env file)
    except Exception as e:
        print("Error creating or deriving API credentials:", e)

if __name__ == "__main__":
    main()

Accessing Polymarket.com Data in Python

Recently I started exploring arbitrage opportunities in the Polymarket.com world. I quickly realized I would need faster access to the data. So I wrote some Python programs to access the platform for data analytics. The documents for doing this are located in the Polymarket docs. Here’s how it works.

Install py-clob-client

pip install py-clob-client<br><br>

Coinbase Wallet

To perform this first block of code you need a Coinbase wallet. Once you have it setup you need to export your private key.

from py_clob_client.client import ClobClient

host = "https://clob.polymarket.com"
private_key = "YOUR_PRIVATE_KEY_GOES_HERE"
chain_id = 137  # Polygon Mainnet

# Initialize the client with private key
client = ClobClient(host, key=private_key, chain_id=chain_id)

api_key_data = client.create_api_key()

print(api_key_data)

Creating keys.py

We can take this outputted data and create our keys.py which will hold our keys.For some reason, the api_passphrase and rename it api_key while commenting out the original api_key. I left the api_secret and original api_passphrase. Now that I have my keys.py I can reference it in my main code


Extracting all of the data

import csv
import json
from py_clob_client.client import ClobClient
from keys import api_key  # Import only the API key
from py_clob_client.clob_types import OpenOrderParams

# Replace with your actual host and chain ID
host = "https://clob.polymarket.com"
chain_id = 137  # Polygon Mainnet

# Initialize the client with only the host, key, and chain_id
client = ClobClient(
    host,
    key=api_key,
    chain_id=chain_id
)

# Initialize variables for pagination
markets_list = []
next_cursor = None

# Fetch all available markets using pagination
while True:
    try:
        # Print the cursor value for debugging
        print(f"Fetching markets with next_cursor: {next_cursor}")

        # Make the API call based on the cursor value
        if next_cursor is None:
            response = client.get_markets()
        else:
            response = client.get_markets(next_cursor=next_cursor)

        # Print the raw response for debugging
        print(f"API Response: {json.dumps(response, indent=2)}")

        # Check if the response is successful and contains data
        if 'data' not in response:
            print("No data found in response.")
            break

        markets_list.extend(response['data'])
        next_cursor = response.get("next_cursor")

        # Exit loop if there's no next_cursor indicating no more data to fetch
        if not next_cursor:
            break

    except Exception as e:
        # Print the exception details for debugging
        print(f"Exception occurred: {e}")
        print(f"Exception details: {e.__class__.__name__}")
        print(f"Error message: {e.args}")
        break

# Debugging step: Print out the raw data to understand its structure
print("Raw Market Data:")
print(json.dumps(markets_list, indent=2))

# Dynamically extract all keys from the markets to create the CSV columns
csv_columns = set()
for market in markets_list:
    csv_columns.update(market.keys())
    # Also include nested keys like tokens
    if 'tokens' in market:
        csv_columns.update({f"token_{key}" for token in market['tokens'] for key in token.keys()})

csv_columns = sorted(csv_columns)  # Sort columns alphabetically for consistency

# Writing to CSV
csv_file = "markets_data.csv"
try:
    with open(csv_file, 'w', newline='') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=csv_columns)
        writer.writeheader()
        for market in markets_list:
            row = {}
            for key in csv_columns:
                # Handling nested 'tokens' structure
                if key.startswith("token_"):
                    token_key = key[len("token_"):]
                    row[key] = ', '.join([str(token.get(token_key, 'N/A')) for token in market.get('tokens', [])])
                else:
                    row[key] = market.get(key, 'N/A')
            writer.writerow(row)
    print(f"Data has been written to {csv_file} successfully.")
except IOError as e:
    print(f"Error writing to CSV: {e}")

Output CSV

If all goes as planned you will now have a giant CSV file named markets_data.csv with all the different markets and their values. You can now build on this code to manipulate it to your needs.

Unconventional Success: A Fundamental Approach to Personal Investment by David F. Swensen 

I’ve had Unconventional Success by David F. Swensen on my shelf for five years, but it took me a while to finish. The book is somewhat dense and challenging, yet it offers valuable insights, particularly about the effects of drawdown on a portfolio. Swensen, Yale’s CIO for 36 years, managed to achieve an impressive 12% annual return during his tenure.

One key takeaway is that while the S&P 500 generally outperforms many strategies, certain portfolios can do better overall by minimizing drawdowns. Swensen emphasizes several principles that are common in investment literature:

  1. Equities Should Dominate: Despite being riskier, equities offer higher long-term returns.
  2. Passive Investing Over Active Management: Costs significantly impact your portfolio, so minimize them.
  3. Diversification Is Essential: A portfolio solely composed of equities will suffer from severe drawdowns, which can take years to recover from. A well-balanced portfolio mitigates this risk.
  4. Avoid Market Timing: Base your strategy on long-term thinking.
  5. Rebalancing Is Crucial: Regularly sell overperforming assets and buy underperforming ones.
  6. Consider Tax Implications: Be aware of the tax consequences when buying or selling assets.
  7. Stay Disciplined: Don’t let emotions dictate your investment decisions.

Swensen’s Model Portfolio

Swensen’s recommended allocation includes:

  • U.S. Equities: 30%
  • International Developed Market Equities: 15%
  • Emerging Market Equities: 5%
  • REITs: 20%
  • U.S. Treasury Bonds: 15%
  • TIPS: 15%

Hypothetical Portfolios

I compiled and backtested several hypothetical portfolios based on Swensen’s principles. While most failed to outperform the S&P 500 over a 20-year period, one aggressive portfolio did manage to do so, primarily due to its better handling of drawdowns during the 2008-2009 recession.

Conservative Portfolio: $45,293Conservative B Portfolio: $38,916
Moderate Portfolio: $54,785Moderate B Portfolio: $60,839
Aggressive Portfolio: $64,137Aggressive B Portfolio: $93,856
S&P 500 (SPY): $80,315

Portfolio Allocations

Original Portfolios

  1. Conservative Portfolio:
    • 25% VTI, 10% EFA, 5% VWO, 15% VNQ, 25% IEF, 20% TIP
  2. Moderate Portfolio:
    • 30% VTI, 15% EFA, 10% VWO, 15% VNQ, 15% IEF, 15% TIP
  3. Aggressive Portfolio:
    • 40% VTI, 20% EFA, 15% VWO, 10% VNQ, 10% IEF, 5% TIP

B-Series Portfolios

  1. Conservative B Portfolio:
    • 20% VTSAX, 10% VEA, 5% VWO, 15% VNQ, 25% VBTLX, 25% VIPSX
  2. Moderate B Portfolio:
    • 25% VTSAX, 15% VEA, 10% VWO, 20% VNQ, 15% VBTLX, 15% VIPSX
  3. Aggressive B Portfolio:
    • 35% VTSAX, 20% VEA, 10% VWO, 20% VNQ, 10% VBTLX, 5% VIPSX

Benchmark

  1. S&P 500 (SPY)

While beating the S&P 500 over the long term is challenging, Swensen’s strategies offer a solid foundation for those looking to manage risk and optimize returns. For most investors, simply investing in the S&P 500 might be the best approach, but Swensen shows there are ways to potentially outperform through strategic portfolio management.

Annual Returns (2003 – 2023)

2003

PortfolioReturn
Conservative Portfolio18.34%
Moderate Portfolio19.90%
Aggressive Portfolio21.45%
Conservative B13.39%
Moderate B18.30%
Aggressive B23.95%
S&P 500 (SPY)28.18%

2004

PortfolioReturn
Conservative Portfolio11.55%
Moderate Portfolio12.49%
Aggressive Portfolio14.08%
Conservative B7.42%
Moderate B19.80%
Aggressive B21.28%
S&P 500 (SPY)10.70%

2005

PortfolioReturn
Conservative Portfolio8.62%
Moderate Portfolio10.46%
Aggressive Portfolio12.24%
Conservative B7.57%
Moderate B10.68%
Aggressive B11.77%
S&P 500 (SPY)4.83%

2006

PortfolioReturn
Conservative Portfolio18.71%
Moderate Portfolio21.07%
Aggressive Portfolio23.19%
Conservative B19.47%
Moderate B22.66%
Aggressive B26.71%
S&P 500 (SPY)15.85%

2007

PortfolioReturn
Conservative Portfolio6.92%
Moderate Portfolio7.64%
Aggressive Portfolio9.07%
Conservative B5.04%
Moderate B6.09%
Aggressive B7.82%
S&P 500 (SPY)5.14%

2008

PortfolioReturn
Conservative Portfolio-24.53%
Moderate Portfolio-27.55%
Aggressive Portfolio-31.46%
Conservative B-24.30%
Moderate B-27.57%
Aggressive B-33.20%
S&P 500 (SPY)-36.81%

2009

PortfolioReturn
Conservative Portfolio22.78%
Moderate Portfolio25.46%
Aggressive Portfolio27.59%
Conservative B26.79%
Moderate B33.32%
Aggressive B39.89%
S&P 500 (SPY)26.37%

2010

PortfolioReturn
Conservative Portfolio14.65%
Moderate Portfolio15.73%
Aggressive Portfolio16.57%
Conservative B12.81%
Moderate B18.72%
Aggressive B23.66%
S&P 500 (SPY)15.06%

2011

PortfolioReturn
Conservative Portfolio5.33%
Moderate Portfolio3.66%
Aggressive Portfolio3.92%
Conservative B3.07%
Moderate B4.50%
Aggressive B0.33%
S&P 500 (SPY)1.89%

2012

PortfolioReturn
Conservative Portfolio14.20%
Moderate Portfolio14.95%
Aggressive Portfolio16.05%
Conservative B11.49%
Moderate B13.46%
Aggressive B19.45%
S&P 500 (SPY)15.99%

2013

PortfolioReturn
Conservative Portfolio10.62%
Moderate Portfolio14.34%
Aggressive Portfolio16.07%
Conservative B10.61%
Moderate B12.44%
Aggressive B22.27%
S&P 500 (SPY)32.31%

2014

PortfolioReturn
Conservative Portfolio8.49%
Moderate Portfolio10.03%
Aggressive Portfolio11.11%
Conservative B7.99%
Moderate B11.00%
Aggressive B13.04%
S&P 500 (SPY)13.46%

2015

PortfolioReturn
Conservative Portfolio-1.37%
Moderate Portfolio-2.23%
Aggressive Portfolio-3.02%
Conservative B-1.60%
Moderate B-1.42%
Aggressive B-2.27%
S&P 500 (SPY)1.25%

2016

PortfolioReturn
Conservative Portfolio7.71%
Moderate Portfolio9.56%
Aggressive Portfolio10.96%
Conservative B7.62%
Moderate B8.03%
Aggressive B12.17%
S&P 500 (SPY)12.00%

2017

PortfolioReturn
Conservative Portfolio13.75%
Moderate Portfolio18.11%
Aggressive Portfolio21.11%
Conservative B12.78%
Moderate B17.42%
Aggressive B24.71%
S&P 500 (SPY)21.70%

2018

PortfolioReturn
Conservative Portfolio-6.43%
Moderate Portfolio-8.74%
Aggressive Portfolio-11.04%
Conservative B-6.69%
Moderate B-7.04%
Aggressive B-10.27%
S&P 500 (SPY)-4.56%

2019

PortfolioReturn
Conservative Portfolio21.73%
Moderate Portfolio23.58%
Aggressive Portfolio26.23%
Conservative B19.53%
Moderate B21.70%
Aggressive B29.21%
S&P 500 (SPY)31.22%

2020

PortfolioReturn
Conservative Portfolio10.83%
Moderate Portfolio13.58%
Aggressive Portfolio15.56%
Conservative B10.56%
Moderate B11.04%
Aggressive B14.82%
S&P 500 (SPY)18.37%

2021

PortfolioReturn
Conservative Portfolio12.71%
Moderate Portfolio16.57%
Aggressive Portfolio20.73%
Conservative B14.87%
Moderate B17.24%
Aggressive B23.33%
S&P 500 (SPY)28.75%

2022

PortfolioReturn
Conservative Portfolio-17.25%
Moderate Portfolio-18.32%
Aggressive Portfolio-19.45%
Conservative B-17.07%
Moderate B-17.58%
Aggressive B-19.11%
S&P 500 (SPY)-18.17%

2023

PortfolioReturn
Conservative Portfolio14.22%
Moderate Portfolio15.87%
Aggressive Portfolio17.73%
Conservative B13.49%
Moderate B15.92%
Aggressive B17.73%
S&P 500 (SPY)26.19%

I also created a custom GPT for this book. You can find that here.

Building a DIY Powerwall to offset peak demand cost PT3, install

I finally installed this EG4 battery and inverter to power my house. You can read parts 1 and 2 here if you’re curious why I started this project. I did end up purchasing two batteries instead of one. A single inverter can support up to three batteries per the manufacturer. In my current configuration, I have a 28.6kWh capacity(2 batteries in parallel) which so far appears sufficient to support my house in the peak of July for 3 hours.

Too Small

My first attempt at building this project was with one battery with a 14.3kWh capacity. Remember the original goal was to eliminate all energy from the grid between 3-6 PM when energy is very expensive. You can see below in a couple of examples I was using too much energy and the battery would die. Then I would pull energy from the grid as indicated by that red bar. This was the last week before I installed the second battery.

Just Right

Here is the week after installing the second battery giving me a 28.6kWh capacity.


There is still some red in here when I was testing a few things and the battery was off. Also on the 29th I set the state of charge (SOC) level too low and the battery breaker tripped. EG4 recommends not depleting these any less than 20% SOC. This caused me to lose the battery discharging that entire day as indicated by the 3 red bars.

The EG4 interface was a bit tricky to understand at first. But essentially you just want to configure it to discharge the battery during certain hours and stop with the state of charge gets to a certain level.

The SOC cut-off level can also be configured here.

We can then configure the battery to charge starting at midnight

So essentially all the battery is doing is discharging between 3-6PM and charging at midnight.

Measuring current

This inverter also comes with CT clamps. You stick both of these on each leg of your 220v from your electricity provider. This allows you to monitor the amount of electricity you’re using for your entire house so you don’t back feed any electricity into the grid. You can check these options below to make sure the inverter does not send any electricity upstream.

Cost

Because I had to purchase two batteries and an inverter the cost was a bit more than I anticipated. My total cost for the main components was $11,683.30. I bought it from a local company in Arizona, San Tan Solar. The Residential Clean Energy Credit gives you 30% off the cost bringing the final number to $8,178.31 for 28.6kWh of battery and an inverter. The ultimate goal is to offset all of my energy from 2-8 PM with the solar and the current battery. This is just phase one of a larger project that will include solar. However, now that the inverter is installed I am ready to simply plug in solar panels.

Savings

The savings will be a little difficult to calculate until I’ve generated some usage statistics in my new house. However, below is SRP’s standard rates. We can now switch to the SRP 3-6 program and get all of our energy to about 10c per kWh which is a 30-40% savings. Again, the ultimate goal is to convert this into a solar/battery setup and offset all of our usage from 2-8 PM. This will drastically cut costs as all of our electricity will then be 5c per kWh reducing the cost 60-70% per kWh.

Building a DIY Powerwall to offset peak demand cost PT2, sizing the battery

In the first part of this series, we discussed why building a DIY Powerwall is a smart move to offset peak demand costs. In this part, we’ll focus on how to determine the appropriate battery size for your needs using historical usage data from your SRP bills. The Python program below will output these charts and recommendations.

Output

The max you used during any 2-8 PM period is 58.90 kWh on 2021-09-05. Based on historical usage, this battery size would eliminate your electricity usage during peak hours.

The average you used during all 2-8 PM periods is 10.92 kWh. Based on historical usage, a battery of this size would eliminate your peak electricity usage on average.

If you did not have solar, you would need a battery with a size of 87.20 kWh to eliminate the maximum demand during peak hours. This maximum was recorded on 2021-09-05.

If you did not have solar, you would need a battery with a size of 39.04 kWh to eliminate the average demand during peak hours.

If you did not have solar, you would need a battery with a size of 232.80 kWh to power your house for a full day based on the maximum daily consumption. This maximum was recorded on 2021-08-03.

If you did not have solar, you would need a battery with a size of 116.08 kWh to power your house for a full day based on the average daily consumption.

Because you have solar, this reduces your battery size by 32.45% to eliminate all your peak energy.

Because you have solar, this reduces your battery size by 72.02% to eliminate on average all of your peak energy.

Collecting your data

To use this program, you need to download your hourly usage data from SRP:

  1. Log in to Your SRP Account:
    • Navigate to the usage section.
    • Select hourly usage and choose your date range.
    • Export the data to Excel for the categories: net energy, generation, and usage. If you do not have solar, you may only have usage data, which is fine.
  2. Data Export:
    • Download the data for May through October to focus on summer consumption months, as winter usage without AC is significantly lower.
    • Export data for multiple past years to allow the program to determine maximum and average values accurately.



You should now have some files that look like this.

With your data files ready, you can now run the Python program:

Time to buy the equipment

Now that you know your required battery size, you can begin shopping for components and building your DIY Powerwall. Stay tuned for the next part, where we’ll dive into the construction process!