σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademySkills
Ctrl K
AO
+1.2k Learners
LoginJoin ↗
Skills
AO
+1.2k Learners
Login
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python skill›Module 2 · NumPy & pandas for market data›Topic 2.1·~45 minBeginner

NumPy arrays and dtypes

Skill positionModule 2 of 11 · Topic 1 of 20
2.1 NumPy arrays and dtypes
—Lab score— / 100Total XP—Streak—

Why arrays, and what an array is

A Python list can hold anything, which makes it flexible but slow for numbers: every element is a separate object. NumPy adds the ndarray, a block of memory holding numbers of one single type laid out one after another. Operating on the whole block in compiled code is typically tens of times faster than a Python loop, and it uses far less memory. Almost every quantitative library (pandas, SciPy, scikit-learn) is built on it. Import it by convention as import numpy as np.

import numpy as np

# Create arrays
prices = np.array([184.25, 185.0, 183.2])
print(prices)                       # [184.25 185.   183.2 ]
print(np.zeros(3))                  # [0. 0. 0.]
print(np.arange(0, 10, 3))          # [0 3 6 9]
print(np.linspace(0, 1, 5))         # [0.   0.25 0.5  0.75 1.  ]

# An array knows its shape
table = np.array([[1, 2, 3], [4, 5, 6]])
print(table.shape, table.ndim, table.size)   # (2, 3) 2 6

Creating arrays

np.array(list) converts a list (or a list of lists for two dimensions). np.zeros(n) and np.ones(n) make filled arrays, and np.zeros((rows, cols)) takes a shape tuple. np.arange(start, stop, step) works like range but allows float steps and excludes stop; because of rounding, prefer np.linspace(start, stop, num), which gives exactly num evenly spaced points and includes both ends. Every array has .shape (the size in each dimension), .ndim (number of dimensions) and .size (total number of elements).

import numpy as np

# arange with floats can surprise; linspace gives exactly the points you ask for
print(len(np.arange(0, 1, 0.1)))     # 10  (1.0 is excluded)
print(len(np.linspace(0, 1, 11)))    # 11  (both ends included)

# Shapes and sizes
grid = np.zeros((3, 4))
print(grid.shape, grid.ndim, grid.size)   # (3, 4) 2 12
print(np.ones(2) * 5)                      # [5. 5.]

dtypes: one type for the whole array

Every array has a dtype: int64 (whole numbers), float64 (decimals), bool, and smaller or bigger variants such as float32 or int8. NumPy picks the dtype from the data: integers give int64, a single decimal turns everything into float64, and np.nan (not-a-number, the marker for a missing value) is a float, so it forces float64. Choose a dtype yourself with dtype=..., or convert with .astype(...), which returns a new array. A smaller dtype saves memory (float32 takes half of float64), at the price of precision.

import numpy as np

print(np.array([1, 2, 3]).dtype)            # int64
print(np.array([1, 2.5, 3]).dtype)          # float64  (one decimal upgrades everything)
print(np.array([True, False]).dtype)        # bool
print(np.array([1, 2, np.nan]))             # [ 1.  2. nan]  (nan is a float)

# astype returns a new array; smaller dtypes use less memory
prices = np.zeros(1000)
print(prices.nbytes)                        # 8000
print(prices.astype(np.float32).nbytes)     # 4000
print(np.array(["1.5", "2"], dtype=float))  # [1.5 2. ]  (text converted to numbers)

Casting traps: truncation and overflow

Converting decimals to integers with .astype(int) truncates toward zero, and floats cannot represent most decimals exactly, so 19.99 * 100 is 1998.9999999999998 and truncates to 1998, one cent short. To convert prices to whole cents, round first: np.round(prices * 100).astype(np.int64). Integer dtypes also have a fixed range and wrap around silently: an int8 holds -128 to 127, so 100 * 2 becomes -56. Use int64 for money and counts, and remember that dividing integers with / always gives floats while // floors.

import numpy as np

# Truncation: astype(int) cuts the decimals off
print(np.array([1.9, -1.9]).astype(int))              # [ 1 -1]
print(19.99 * 100, int(19.99 * 100))                  # 1998.9999999999998 1998
print(np.round(np.array([19.99]) * 100).astype(np.int64))   # [1999]

# Overflow: an int8 wraps around silently
small = np.array([100, 50], dtype=np.int8)
print(small * 2)                                      # [-56 100]

# / always gives floats, // floors
counts = np.array([1, 2, 3])
print(counts / 2, counts // 2)                        # [0.5 1.  1.5] [0 1 1]
Look at shape and dtype firstWhen NumPy code misbehaves, print .shape and .dtype of every array involved before anything else: a surprising int64 where you expected float64, or a shape of (5, 1) instead of (5,), explains most bugs. Prefer building arrays with NumPy functions (np.linspace, np.asarray, astype) instead of Python loops; the labs reject loops for exactly this reason.
  • np.array, zeros, ones, arange, linspace create arrays; .shape, .ndim, .size describe them.
  • One dtype per array: int64, float64, bool; astype converts into a new array.
  • astype(int) truncates (round first); small integer dtypes wrap around silently; nan forces floats.

Next up: indexing and slicing arrays, picking out rows, columns, windows and values that meet a condition.

Lab · what's graded

  • Lay out evenly spaced points with make_grid25 pts
  • Turn mixed raw values into floats with to_float_array25 pts
  • Report shape, size and dtype with describe_array25 pts
  • Convert prices to whole cents safely with to_cents25 pts
Explorer · lab-34-1
▾ lab-34-1
…
bash · in-browser
learner@quantcraft:~/lab-34-1$
Python not loaded yetPythonLn 1, Col 1Spaces: 4UTF-8

Reset this topic?

Everything in lab-34-1 goes back to the starter files and the terminal is cleared. Your current solution will be lost — this can't be undone.

Will be reset
  • main.py → starter code
  • Terminal history and test output
  • Unsubmitted changes
Will be kept
  • Best lab score
  • Your XP and streak
  • Lecture progress and notes

Log in to run your code.

Every lecture is free to read. Create an account or log in to run code, run tests and submit this lab.

  • In-browser IDE with a bash terminal — nothing to install
  • Instant grading, XP and your place on the skill
Create an accountLog in
OR
Continue with GitHub