Python for Algo Trading: A Step-by-Step Guide for Beginners

Hi @Everyone,

If you are building an algo trading system on the Dhan API, there is one skill that separates traders who can only use AI tools from traders who can actually direct them: a working knowledge of Python.

It is tempting to think that with tools like Claude, ChatGPT, and Cursor now available, learning to code yourself has become optional. After all, why not simply ask an AI to “build the algo” and be done with it?

Here is the problem with that shortcut.

Analogy — The Cab Ride Imagine you are new to Mumbai and you book a cab. You sit back, relax, and scroll through reels while the driver takes you to your destination. Now imagine the driver takes a wrong turn. Because you were not paying attention to the map, you would never even know you were being driven to the wrong place — let alone be able to correct it.

AI tools work the same way. Every AI product carries some version of the same disclaimer: answers may not always be factually correct, and the AI can make mistakes. If you don’t understand Python at all, you have no way of knowing when your AI-generated algo has gone off course. You will never be able to reach your destination reliably.

This is exactly why a beginner in algo trading should still learn the fundamentals of Python — not to write every line by hand forever, but to be able to direct AI correctly, read what it produces, and catch mistakes before they cost you money.

The good news: Python is genuinely one of the easier programming languages to pick up, and if you’re already comfortable with Excel formulas, you already have the right mindset to learn it. This guide walks through the ten core Python building blocks every algo trader needs, using the same examples and workflow used while building live trading algorithms on the Dhan API.


Setting Up: Run Mode vs. Debug Mode

Before writing any code, it helps to understand the two ways a Python file can be executed inside an editor like Cursor or VS Code:

Mode What It Does When to Use It
Run Executes the entire program from start to finish in one go Once your code is complete and tested
Debug Executes the program line by line, pausing wherever you place a breakpoint While learning, testing, or troubleshooting

fig_02_python_data_types
Figure 1: The six core Python building blocks covered in this guide.

Tip — Use Debug Mode While Learning A breakpoint is a marker (usually shown as a red dot next to a line number) that tells the debugger where to pause. When you run a file in debug mode, execution stops the moment it reaches your breakpoint, and you can inspect the value of every variable at that exact point in the code. This is the single best way to understand what a new script is actually doing, line by line, instead of guessing from the output alone.


1. Numbers: Integers and Floats

Python organizes numeric data into two main types:

  • Integer (int) — a whole number with no decimal point. Example: lot_size = 65
  • Float — a number that includes a decimal point. Example: ltp = 755.65

With both types, you can perform the usual arithmetic — addition, subtraction, multiplication, and division — exactly as you would in an Excel formula. You can also compare numeric values against each other, which is the foundation of every trading condition you will eventually write:

# Comparing values
rsi > 60    # Is RSI greater than 60?
rsi < 40    # Is RSI less than 40?

These two lines look simple, but they are quite literally the building blocks of every entry and exit rule you will code into a strategy.

Variables: Naming Your Data

Whenever you write a statement like:

lot_size = 65

Python takes the value on the right (65) and stores it inside the name on the left (lot_size). This is called a variable. From that point forward, anywhere you use lot_size in your code, Python substitutes in the value 65.

Every manual trading habit you already have translates directly into variables:

max_trade = 3          # Maximum number of trades allowed
capital = 100000        # Total capital available

If you can build a formula-driven spreadsheet in Excel, you already think in exactly the structure Python needs — it is genuinely not a big deal.

Converting Floats to Integers

Here’s a real scenario that comes up constantly in options trading. Suppose you calculate the number of shares or contracts to buy using:

quantity = capital_per_trade / ltp

This division often produces a decimal result — for example, 132.132. But brokers like Dhan do not allow fractional quantities. You cannot place an order for 132.132 units of anything.

The fix is to wrap the result inside Python’s built-in int() function, which strips away everything after the decimal point:

quantity = int(capital_per_trade / ltp)
# 132.132 becomes 132

Note: int() truncates rather than rounds — it simply removes the decimal portion. For an order-quantity calculation, this is exactly the behavior you want, since rounding up could mean requesting more capital than you actually allocated.

Equality Checks

Python also lets you check whether two values are exactly equal using == (two equal signs, not one):

rsi == 60.55   # True, if rsi currently equals exactly 60.55

This is a different operation from =, which assigns a value. == only asks a yes/no question — it never changes anything.


2. Strings: Working with Text

A string is simply text — any sequence of letters, numbers, or symbols wrapped inside quotation marks. Anywhere you need to store or display words instead of numbers, you’re working with a string.

symbol = "TCS"
call_name = "2JUN 23950 CALL"
entry_price = 160

Strings become genuinely useful once you start combining them with variables to build readable messages — for example, a trade confirmation you might print to your terminal or log file:

message = "Entry in " + call_name + " with price " + str(entry_price)
print(message)
# Output: Entry in 2JUN 23950 CALL with price 160

Why do some values need quotes and others don’t? Quotes are only required on the right-hand side of an = sign, and only when the value itself is text. call_name = "2JUN 23950 CALL" needs quotes because the value is a string. entry_price = 160 does not, because 160 is a number. The variable name on the left never takes quotes, regardless of type.


3. Lists: Ordered Collections

A list is Python’s version of a watchlist — an ordered collection of items, stored under a single variable name.

watchlist = ["BANKBARODA", "BANKINDIA", "TORRENTPOWER", "SPARC", "LTFOODS", "VBL", "UNIONBANK"]

Every list begins and ends with square brackets [ ], with each item separated by a comma.

Indexing: Finding an Item’s Position

The single most important thing to understand about Python lists is that counting starts at zero, not one.

fig_03_list_indexing
Figure 2: Positive indexes count from the start of the list (0, 1, 2…); negative indexes count backward from the end (-1, -2, -3…).

watchlist[0]   # 'BANKBARODA'  — first item
watchlist[2]   # 'TORRENTPOWER' — third item
watchlist[-1]  # 'UNIONBANK'    — last item
watchlist[-2]  # 'VBL'          — second-last item

This negative indexing is especially useful later when working with live market data — the most recent candle in a price series is almost always addressed as [-1].

Adding Items with .append()

To add a new item to the end of an existing list, use .append():

watchlist.append("ZEEL")
print(watchlist)
# ['BANKBARODA', 'BANKINDIA', ..., 'UNIONBANK', 'ZEEL']

Practice tip: The fastest way to internalize how lists behave is to run one in debug mode and print it after every change. Watching the list grow one item at a time, in real time, makes indexing click far faster than reading about it.


4. Dictionaries: Key–Value Relationships

A dictionary stores data as pairs — a key and its corresponding value. Use a dictionary any time you need to describe a relationship between a label and a piece of data.

fig_04_dictionary_structure
Figure 3: A dictionary maps each key directly to its value — here, OHLC price fields.

ohlc = {
    "open": 100,
    "high": 105,
    "low": 95,
    "close": 102
}

print(ohlc["close"])   # 102

This pattern shows up constantly in algo trading — for example, storing a lot size dictionary so your code can look up the correct lot size for any symbol on demand:

lot_size = {
    "ACC": 400,
    "CIPLA": 700
}

print(lot_size["CIPLA"])   # 700

A dictionary’s structure always follows the same rhythm: a key, followed by its value, followed by the next key, followed by its value — just like a word in a dictionary followed by its meaning.


5. For Loops: Scanning a Watchlist Automatically

Think about how manual scanning normally works: you open HDFC Bank’s chart, check the RSI, close it, open ICICI Bank, check RSI again, then State Bank of India, and so on — one stock at a time, by hand. Depending on your watchlist size, this can easily consume several hours a day.

A for loop automates exactly this repetitive, sequential process.

fig_05_for_loop_flow
Figure 4: A for loop repeats the same action for every item in a list, one at a time, until the list is exhausted.

watchlist = ["BANKBARODA", "BANKINDIA", "TORRENTPOWER"]

for name in watchlist:
    print("Scanning for", name)

Output:

Scanning for BANKBARODA
Scanning for BANKINDIA
Scanning for TORRENTPOWER

On each pass through the loop, the variable name takes on the next value from the list — first "BANKBARODA", then "BANKINDIA", then "TORRENTPOWER" — until every item has been visited exactly once. The loop then stops automatically once it reaches the end of the list.

This is the mechanism that turns a multi-hour manual scanning routine into a script that runs in seconds.


6. If–Else: Turning Rules into Decisions

Once your loop is scanning through stocks, you need a way to act on what it finds. That’s the role of if–else logic — it lets your code make a decision based on a condition.

fig_07_if_else_flow
Figure 5: A simple two-condition trading rule expressed as if–elif–else logic.

if rsi > 60:
    buy()              # Place buy order, set stop-loss, update order book
elif rsi < 40:
    sell()              # Place sell order, update order book
else:
    pass                # Condition not met — do nothing, move to next stock

Python checks each condition from top to bottom. If the first (if) condition is True, it executes that block and skips the rest. If it’s False, Python checks the next condition (elif), and so on. If none of the conditions are met, nothing happens — the code simply continues to the next stock in the loop.

Combining a For Loop with If–Else

This is where the real power shows up: looping and decision-making combined.

watchlist = ["BANKBARODA", "BANKINDIA", "SPARC", "LTFOODS"]

for name in watchlist:
    if len(name) >= 9:
        print(name, "— BUY condition met")
    elif len(name) < 5:
        print(name, "— SELL condition met")
    else:
        print(name, "— no condition met, skipping")

Here, the loop visits every stock one by one, and for each stock, the if–else block independently checks whether a condition is true. This exact pattern — loop through a watchlist, evaluate a condition for each item, act accordingly — is the structural skeleton of almost every scanning algorithm you will ever build.


7. While Loops: Running Continuously

A for loop runs a fixed number of times — exactly as many times as there are items in your list. A while loop behaves differently: it keeps running indefinitely, for as long as its condition stays True.

Live trading itself is essentially a while loop. You start your algorithm at market open, and it keeps running continuously — checking prices, watching for signals — until you deliberately stop it or a specific exit condition is met.

fig_08_while_loop_break
Figure 6: A while loop runs indefinitely until an explicit break condition stops it.

number = 1
while True:
    print(number)
    number += 1
    if number == 6:
        break

Warning: A while True: loop with no break condition will run forever — it will only stop if you manually interrupt the program or the machine running it shuts down. Always pair a while loop with a clear exit condition, whether that’s a break statement, a time-based cutoff, or a market-close check.


8. DataFrames: The Real Shape of Market Data

This is arguably the most important concept in the entire list, because it’s the structure that every price chart actually takes once it reaches your code.

A DataFrame organizes market data the same way a spreadsheet does — in rows and columns. Each row typically represents one candle, and the columns hold Open, High, Low, Close, and Volume.

fig_01_candlestick_rsi
Figure 7: Once OHLC data sits inside a DataFrame, you can chart it, calculate indicators like RSI, and query any value directly — model data shown for illustration.

chart.columns
# Index(['Open', 'High', 'Low', 'Close', 'Volume'], dtype='object')

chart["Close"]                       # the full Close column
(chart["Close"] + chart["Open"]) / 2  # a custom calculated column

Accessing Specific Rows

Just like list indexing, -1 refers to the last row, and -2 refers to the second-to-last row:

chart.iloc[-1]    # the most recent candle
chart.iloc[-2]    # the previous candle

Important — The Live Candle When you pull data from a broker API like Dhan’s, the response usually includes the candle that is still forming (the current, incomplete one). This means chart.iloc[-1] may not represent a completed candle — it could still be updating. For most scanning logic, you’ll want to reference chart.iloc[-2] as your last fully completed candle, and treat chart.iloc[-1] as the live, in-progress price action.

Common DataFrame Operations

Operation Code Purpose
Average volume chart["Volume"].mean() Typical trading activity
Highest high chart["High"].max() Resistance reference point
Lowest low chart["Low"].min() Support reference point
Yesterday’s high chart["High"].iloc[-2] Prior-day reference
RSI on last candle chart["RSI"].iloc[-1] Current momentum reading

Worked Example: Calculating a Gap

A gap-up or gap-down scan is a common condition in momentum strategies. It’s calculated as the percentage difference between today’s open and yesterday’s close:

gap_percent = ((today_open - yesterday_close) / yesterday_close) * 100

if gap_percent > 2:
    print("Significant gap-up:", gap_percent, "%")

fig_06_ema_crossover_scan
Figure 8: Once conditions like a gap, an RSI threshold, or a moving-average crossover are calculated from a DataFrame, they can trigger buy or sell markers exactly like this — model data shown for illustration.

Once this single calculated value exists, your algo can act on it directly — exactly the same way it acts on RSI, EMA crossovers, or any other computed condition.


Bringing It All Together

Every one of these ten building blocks — integers, floats, variables, strings, lists, dictionaries, for loops, if–else logic, while loops, and DataFrames — combines to form a working algorithm. None of them are complicated in isolation. What makes an algo strategy feel complex is simply how many of these pieces are stacked together at once.

The comparison to when you first entered the stock market is a useful one. You didn’t know what a lot size was, or what “expiry” meant, or how a limit order worked — until you learned those words, one at a time. Python works exactly the same way. Today you met ten new “words.” With practice, they will feel just as natural as NSE, expiry, and lot size do now.

And here’s the encouraging part: you don’t need to memorize every syntax rule or become a Python expert. AI tools are genuinely excellent at handling the fine details of syntax. Your job is to understand these concepts well enough to direct the AI accurately, read its output critically, and know when something has gone wrong — the same way you’d want to know if your cab driver took a wrong turn.


Homework: Practice Before the Next Video

  1. Open the practice file (linked in the Resources section below) in your editor.

  2. Set a breakpoint and run the file in debug mode.

  3. Step through each concept — integers, floats, strings, lists, dictionaries, loops, and if–else — one at a time, and observe the output at every step.

  4. Open the debug console and experiment freely. For example, try:

    ltp + 10
    ltp - 10
    
  5. Modify the if–else conditions with your own numbers and watch how the output changes.

Spending even a single focused hour actively experimenting with these blocks — rather than passively reading about them — is what will make Python concepts genuinely click.

Getting Help

If you run into questions while practicing, you can post them on the Made For Trade community forum (see Resources). When asking for support, keep these two rules in mind:

Warning — Never Share Sensitive Credentials Never post your Client Code, PIN, or TOTP/API secret in a public forum, chat, or support ticket. Anyone with access to this information can place orders directly on your trading account — treat it with the same seriousness as your bank account details.

Tip — Formatting Your Code Correctly Always paste code using the forum’s dedicated code block feature rather than pasting it as plain text. Plain-text code loses all indentation and formatting, which makes it very difficult for anyone to read or help you debug. A properly formatted code block preserves structure, coloring, and indentation exactly as it appears in your editor.


What’s Next

This post covered the foundational Python concepts used throughout the Complete Algo Series. In the next part, these same building blocks — combined with the Dhan API — are used to construct an actual momentum scanner, followed by order placement, deployment, and finally options order execution.

Practice the concepts in this guide thoroughly before moving on — everything that follows builds directly on top of them.


Resources