or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

alerts-screening.mdauthentication.mdindex.mdmarket-data.mdoptions.mdpaper-trading.mdportfolio.mdstreaming.mdtrading.md

paper-trading.mddocs/

0

# Paper Trading

1

2

Complete paper trading simulation environment that mirrors live trading functionality for testing strategies without real money. The paper trading client inherits from the main webull class with specialized methods for simulation.

3

4

## Prerequisites

5

6

Paper trading requires:

7

1. Webull account with paper trading enabled

8

2. Successful login (same credentials as live account)

9

10

## Capabilities

11

12

### Paper Trading Client

13

14

Specialized client class for paper trading operations.

15

16

```python { .api }

17

class paper_webull(webull):

18

def __init__(self):

19

"""

20

Initialize paper trading client.

21

22

Inherits all functionality from main webull class but routes

23

trading operations to paper trading endpoints.

24

"""

25

```

26

27

Usage example:

28

29

```python

30

from webull import paper_webull

31

32

# Initialize paper trading client

33

paper_wb = paper_webull()

34

35

# Login (same credentials as live account)

36

paper_wb.login('your_email@example.com', 'your_password')

37

```

38

39

### Paper Account Management

40

41

Get paper account information and virtual portfolio details.

42

43

```python { .api }

44

def get_account(self):

45

"""

46

Get paper account information and virtual portfolio summary.

47

48

Returns:

49

dict: Paper account details including:

50

- totalValue: Total virtual portfolio value

51

- cashBalance: Virtual cash balance

52

- buyingPower: Virtual buying power

53

- dayChange: Daily change in portfolio value

54

- totalProfitLoss: Total unrealized P&L

55

- positions: Number of positions held

56

"""

57

58

def get_account_id(self):

59

"""

60

Get paper trading account ID.

61

62

Returns:

63

str: Paper account identifier

64

"""

65

```

66

67

Usage examples:

68

69

```python

70

# Get paper account summary

71

paper_account = paper_wb.get_account()

72

print(f"Paper Portfolio Value: ${paper_account['totalValue']}")

73

print(f"Virtual Cash: ${paper_account['cashBalance']}")

74

print(f"Virtual Buying Power: ${paper_account['buyingPower']}")

75

print(f"Paper P&L: ${paper_account['totalProfitLoss']}")

76

77

# Get paper account ID

78

paper_account_id = paper_wb.get_account_id()

79

print(f"Paper Account ID: {paper_account_id}")

80

```

81

82

### Paper Positions

83

84

Get all current positions in the paper trading account.

85

86

```python { .api }

87

def get_positions(self):

88

"""

89

Get all current positions in paper account.

90

91

Returns:

92

list: List of paper position objects containing:

93

- ticker: Stock symbol information

94

- position: Number of shares (positive for long, negative for short)

95

- cost: Average cost basis per share

96

- marketValue: Current market value of position

97

- unrealizedProfitLoss: Unrealized gain/loss

98

- unrealizedProfitLossRate: Unrealized gain/loss percentage

99

- lastPrice: Last traded price

100

"""

101

```

102

103

Usage example:

104

105

```python

106

# Get paper positions

107

paper_positions = paper_wb.get_positions()

108

109

print("Paper Trading Positions:")

110

for position in paper_positions:

111

symbol = position['ticker']['symbol']

112

shares = position['position']

113

cost = position['cost']

114

market_value = position['marketValue']

115

pnl = position['unrealizedProfitLoss']

116

pnl_pct = position['unrealizedProfitLossRate']

117

118

print(f"{symbol}: {shares} shares @ ${cost:.2f}")

119

print(f" Market Value: ${market_value:.2f}")

120

print(f" P&L: ${pnl:.2f} ({pnl_pct:.2f}%)")

121

```

122

123

### Paper Order Management

124

125

Place, modify, and cancel orders in the paper trading environment.

126

127

```python { .api }

128

def place_order(self, stock=None, tId=None, price=0, action='BUY', orderType='LMT', enforce='GTC', quant=0, outsideRegularTradingHour=True):

129

"""

130

Place a paper trading order.

131

132

Parameters:

133

- stock (str, optional): Stock symbol

134

- tId (int, optional): Ticker ID

135

- price (float): Order price for limit orders

136

- action (str): 'BUY' or 'SELL'

137

- orderType (str): Order type - 'LMT', 'MKT', 'STP', 'STP_LMT'

138

- enforce (str): Time in force - 'GTC', 'DAY', 'IOC', 'FOK'

139

- quant (int): Quantity of shares

140

- outsideRegularTradingHour (bool): Allow extended hours trading

141

142

Returns:

143

dict: Paper order placement result with order ID and status

144

"""

145

146

def modify_order(self, order, price=0, action='BUY', orderType='LMT', enforce='GTC', quant=0, outsideRegularTradingHour=True):

147

"""

148

Modify existing paper trading order.

149

150

Parameters:

151

- order (dict): Existing paper order to modify

152

- price (float): New order price

153

- action (str): New order action

154

- orderType (str): New order type

155

- enforce (str): New time in force

156

- quant (int): New quantity

157

- outsideRegularTradingHour (bool): New extended hours setting

158

159

Returns:

160

dict: Modification result

161

"""

162

163

def cancel_order(self, order_id):

164

"""

165

Cancel paper trading order.

166

167

Parameters:

168

- order_id (str): Paper order ID to cancel

169

170

Returns:

171

dict: Cancellation result

172

"""

173

```

174

175

Usage examples:

176

177

```python

178

# Place paper buy order

179

paper_order = paper_wb.place_order(

180

stock='AAPL',

181

price=150.00,

182

action='BUY',

183

orderType='LMT',

184

enforce='DAY',

185

quant=100

186

)

187

188

print(f"Paper order placed: {paper_order['orderId']}")

189

190

# Modify paper order

191

modified_order = paper_wb.modify_order(

192

order=paper_order,

193

price=148.00, # Lower the price

194

quant=150 # Increase quantity

195

)

196

197

# Cancel paper order

198

cancel_result = paper_wb.cancel_order(paper_order['orderId'])

199

```

200

201

### Paper Order History

202

203

Get current and historical paper trading orders.

204

205

```python { .api }

206

def get_current_orders(self):

207

"""

208

Get all current active paper trading orders.

209

210

Returns:

211

list: List of active paper order objects

212

"""

213

214

def get_history_orders(self, status='Cancelled', count=20):

215

"""

216

Get paper trading order history.

217

218

Parameters:

219

- status (str): Filter by status - 'Cancelled', 'Filled', 'All'

220

- count (int): Number of historical orders to retrieve

221

222

Returns:

223

list: List of historical paper order objects

224

"""

225

```

226

227

Usage examples:

228

229

```python

230

# Get active paper orders

231

active_paper_orders = paper_wb.get_current_orders()

232

print(f"Active paper orders: {len(active_paper_orders)}")

233

234

for order in active_paper_orders:

235

print(f"Order {order['orderId']}: {order['action']} {order['quantity']} {order['symbol']}")

236

237

# Get paper order history

238

paper_history = paper_wb.get_history_orders(status='Filled', count=10)

239

print("Recent filled paper orders:")

240

241

for order in paper_history:

242

print(f"{order['symbol']}: {order['action']} {order['quantity']} @ ${order['avgFilledPrice']}")

243

```

244

245

## Paper Trading Strategy Testing

246

247

### Strategy Backtesting Framework

248

249

```python

250

class PaperTradingStrategy:

251

def __init__(self, paper_wb, initial_capital=100000):

252

self.paper_wb = paper_wb

253

self.initial_capital = initial_capital

254

self.trades = []

255

self.start_time = time.time()

256

257

def execute_strategy(self, symbol, signal, quantity=100):

258

"""Execute trading strategy based on signals."""

259

260

if signal == 'BUY':

261

self.buy_stock(symbol, quantity)

262

elif signal == 'SELL':

263

self.sell_stock(symbol, quantity)

264

265

def buy_stock(self, symbol, quantity):

266

"""Execute buy order in paper account."""

267

try:

268

# Get current price

269

quote = self.paper_wb.get_quote(stock=symbol)

270

current_price = float(quote['close'])

271

272

# Place market buy order

273

order = self.paper_wb.place_order(

274

stock=symbol,

275

action='BUY',

276

orderType='MKT',

277

quant=quantity

278

)

279

280

self.trades.append({

281

'timestamp': time.time(),

282

'symbol': symbol,

283

'action': 'BUY',

284

'quantity': quantity,

285

'price': current_price,

286

'order_id': order['orderId']

287

})

288

289

print(f"BUY {quantity} {symbol} @ ${current_price}")

290

291

except Exception as e:

292

print(f"Buy order failed: {e}")

293

294

def sell_stock(self, symbol, quantity):

295

"""Execute sell order in paper account."""

296

try:

297

# Check if we own the stock

298

positions = self.paper_wb.get_positions()

299

position = None

300

301

for pos in positions:

302

if pos['ticker']['symbol'] == symbol:

303

position = pos

304

break

305

306

if not position or position['position'] < quantity:

307

print(f"Insufficient shares of {symbol} to sell")

308

return

309

310

# Get current price

311

quote = self.paper_wb.get_quote(stock=symbol)

312

current_price = float(quote['close'])

313

314

# Place market sell order

315

order = self.paper_wb.place_order(

316

stock=symbol,

317

action='SELL',

318

orderType='MKT',

319

quant=quantity

320

)

321

322

self.trades.append({

323

'timestamp': time.time(),

324

'symbol': symbol,

325

'action': 'SELL',

326

'quantity': quantity,

327

'price': current_price,

328

'order_id': order['orderId']

329

})

330

331

print(f"SELL {quantity} {symbol} @ ${current_price}")

332

333

except Exception as e:

334

print(f"Sell order failed: {e}")

335

336

def get_performance_report(self):

337

"""Generate strategy performance report."""

338

account = self.paper_wb.get_account()

339

current_value = account['totalValue']

340

341

# Calculate returns

342

total_return = current_value - self.initial_capital

343

return_pct = (total_return / self.initial_capital) * 100

344

345

# Calculate trade statistics

346

total_trades = len(self.trades)

347

buy_trades = len([t for t in self.trades if t['action'] == 'BUY'])

348

sell_trades = len([t for t in self.trades if t['action'] == 'SELL'])

349

350

print("=== PAPER TRADING PERFORMANCE REPORT ===")

351

print(f"Initial Capital: ${self.initial_capital:,.2f}")

352

print(f"Current Value: ${current_value:,.2f}")

353

print(f"Total Return: ${total_return:,.2f} ({return_pct:.2f}%)")

354

print(f"Total Trades: {total_trades} (Buy: {buy_trades}, Sell: {sell_trades})")

355

356

# Show current positions

357

positions = self.paper_wb.get_positions()

358

if positions:

359

print("\nCurrent Positions:")

360

for pos in positions:

361

symbol = pos['ticker']['symbol']

362

shares = pos['position']

363

pnl = pos['unrealizedProfitLoss']

364

pnl_pct = pos['unrealizedProfitLossRate']

365

print(f" {symbol}: {shares} shares, P&L: ${pnl:.2f} ({pnl_pct:.2f}%)")

366

367

return {

368

'initial_capital': self.initial_capital,

369

'current_value': current_value,

370

'total_return': total_return,

371

'return_pct': return_pct,

372

'total_trades': total_trades

373

}

374

375

# Usage example

376

strategy = PaperTradingStrategy(paper_wb, initial_capital=50000)

377

378

# Simulate trading signals

379

symbols = ['AAPL', 'TSLA', 'MSFT']

380

for symbol in symbols:

381

strategy.execute_strategy(symbol, 'BUY', 50)

382

383

# Wait some time and take profits

384

time.sleep(60) # Wait 1 minute

385

386

for symbol in symbols:

387

strategy.execute_strategy(symbol, 'SELL', 25) # Sell half

388

389

# Get performance report

390

performance = strategy.get_performance_report()

391

```

392

393

### Moving Average Crossover Strategy

394

395

```python

396

def moving_average_strategy(paper_wb, symbol, short_period=5, long_period=20):

397

"""

398

Implement simple moving average crossover strategy in paper account.

399

"""

400

401

# Get historical data

402

bars = paper_wb.get_bars(

403

stock=symbol,

404

interval='d1',

405

count=long_period + 10

406

)

407

408

if len(bars) < long_period:

409

print(f"Insufficient data for {symbol}")

410

return

411

412

# Calculate moving averages

413

closes = [float(bar['close']) for bar in bars]

414

415

def simple_ma(prices, period):

416

return sum(prices[-period:]) / period

417

418

short_ma = simple_ma(closes, short_period)

419

long_ma = simple_ma(closes, long_period)

420

421

# Previous MA values for crossover detection

422

prev_short_ma = simple_ma(closes[:-1], short_period)

423

prev_long_ma = simple_ma(closes[:-1], long_period)

424

425

current_price = closes[-1]

426

427

print(f"{symbol} Analysis:")

428

print(f"Current Price: ${current_price:.2f}")

429

print(f"Short MA ({short_period}): ${short_ma:.2f}")

430

print(f"Long MA ({long_period}): ${long_ma:.2f}")

431

432

# Check for crossover signals

433

if prev_short_ma <= prev_long_ma and short_ma > long_ma:

434

# Golden cross - buy signal

435

print("🟢 Golden Cross detected - BUY signal")

436

437

paper_wb.place_order(

438

stock=symbol,

439

action='BUY',

440

orderType='MKT',

441

quant=100

442

)

443

444

elif prev_short_ma >= prev_long_ma and short_ma < long_ma:

445

# Death cross - sell signal

446

print("🔴 Death Cross detected - SELL signal")

447

448

# Check if we have position to sell

449

positions = paper_wb.get_positions()

450

for pos in positions:

451

if pos['ticker']['symbol'] == symbol and pos['position'] > 0:

452

paper_wb.place_order(

453

stock=symbol,

454

action='SELL',

455

orderType='MKT',

456

quant=min(100, pos['position'])

457

)

458

break

459

else:

460

print("➡️ No signal - holding current position")

461

462

# Test strategy on multiple stocks

463

test_symbols = ['AAPL', 'TSLA', 'MSFT', 'NVDA']

464

for symbol in test_symbols:

465

moving_average_strategy(paper_wb, symbol)

466

print("-" * 40)

467

```

468

469

## Complete Paper Trading Example

470

471

```python

472

from webull import paper_webull

473

import time

474

475

def paper_trading_demo():

476

"""Complete paper trading demonstration."""

477

478

# Initialize paper trading client

479

paper_wb = paper_webull()

480

481

try:

482

# Login

483

paper_wb.login('your_email@example.com', 'your_password')

484

print("Logged into paper trading account")

485

486

# Get initial account state

487

initial_account = paper_wb.get_account()

488

print(f"Starting Portfolio Value: ${initial_account['totalValue']}")

489

print(f"Starting Cash: ${initial_account['cashBalance']}")

490

491

# Test trading operations

492

test_symbol = 'AAPL'

493

494

# Get quote

495

quote = paper_wb.get_quote(stock=test_symbol)

496

current_price = float(quote['close'])

497

print(f"{test_symbol} current price: ${current_price}")

498

499

# Place buy order

500

buy_order = paper_wb.place_order(

501

stock=test_symbol,

502

price=current_price * 0.99, # Slightly below market

503

action='BUY',

504

orderType='LMT',

505

enforce='DAY',

506

quant=10

507

)

508

509

print(f"Buy order placed: {buy_order['orderId']}")

510

511

# Check order status

512

current_orders = paper_wb.get_current_orders()

513

print(f"Active orders: {len(current_orders)}")

514

515

# Wait a bit then modify order to market price

516

time.sleep(5)

517

518

if current_orders:

519

order_to_modify = current_orders[0]

520

modified_order = paper_wb.modify_order(

521

order=order_to_modify,

522

price=current_price, # Market price

523

quant=15 # Increase quantity

524

)

525

print(f"Order modified: {modified_order}")

526

527

# Wait for potential fill, then check positions

528

time.sleep(10)

529

530

positions = paper_wb.get_positions()

531

print(f"Current positions: {len(positions)}")

532

533

for pos in positions:

534

symbol = pos['ticker']['symbol']

535

shares = pos['position']

536

pnl = pos['unrealizedProfitLoss']

537

print(f"{symbol}: {shares} shares, P&L: ${pnl}")

538

539

# Place sell order if we have position

540

if positions:

541

for pos in positions:

542

if pos['ticker']['symbol'] == test_symbol and pos['position'] > 0:

543

sell_order = paper_wb.place_order(

544

stock=test_symbol,

545

price=current_price * 1.02, # Slightly above market

546

action='SELL',

547

orderType='LMT',

548

quant=pos['position']

549

)

550

print(f"Sell order placed: {sell_order['orderId']}")

551

break

552

553

# Final account status

554

final_account = paper_wb.get_account()

555

print(f"\nFinal Portfolio Value: ${final_account['totalValue']}")

556

print(f"Final Cash: ${final_account['cashBalance']}")

557

558

# Order history

559

history = paper_wb.get_history_orders(status='All', count=10)

560

print(f"\nOrder History ({len(history)} orders):")

561

for order in history:

562

print(f" {order['symbol']}: {order['action']} {order['quantity']} @ ${order.get('avgFilledPrice', 'N/A')}")

563

564

except Exception as e:

565

print(f"Paper trading error: {e}")

566

567

# Run the demo

568

paper_trading_demo()

569

```

570

571

## Paper vs Live Trading Differences

572

573

Key differences between paper and live trading:

574

575

1. **Execution**: Paper orders may fill at prices that wouldn't be available in live markets

576

2. **Slippage**: Paper trading doesn't account for bid-ask spreads and market impact

577

3. **Liquidity**: All paper orders assume unlimited liquidity

578

4. **Emotions**: No real money means no emotional pressure

579

5. **Market Hours**: Paper trading may have different hours than live markets

580

581

Use paper trading to:

582

- Test strategies without risk

583

- Learn the API and order types

584

- Practice portfolio management

585

- Validate trading algorithms

586

587

Remember to account for these differences when transitioning to live trading.

588

589

## Social Trading Features

590

591

Paper trading includes access to social trading features for community interaction and learning from other traders.

592

593

### Social Posts

594

595

Get social trading posts and discussions from the community.

596

597

```python { .api }

598

def get_social_posts(self, topic, num=100):

599

"""

600

Get social trading posts for a specific topic.

601

602

Parameters:

603

- topic (str): Topic or symbol to get posts for

604

- num (int, optional): Number of posts to retrieve (default: 100)

605

606

Returns:

607

list: Social posts with user comments, likes, and engagement data

608

"""

609

```

610

611

### Social Home Feed

612

613

Access the social home feed with trending discussions and popular content.

614

615

```python { .api }

616

def get_social_home(self, topic, num=100):

617

"""

618

Get social home feed content.

619

620

Parameters:

621

- topic (str): Topic filter for home feed content

622

- num (int, optional): Number of feed items to retrieve (default: 100)

623

624

Returns:

625

list: Home feed content with trending posts and discussions

626

"""

627

```

628

629

Usage example:

630

631

```python

632

from webull import paper_webull

633

634

paper_wb = paper_webull()

635

paper_wb.login('your_email@example.com', 'your_password')

636

637

# Get social posts for AAPL

638

aapl_posts = paper_wb.get_social_posts('AAPL', num=50)

639

print(f"Found {len(aapl_posts)} posts about AAPL")

640

641

for post in aapl_posts[:5]: # First 5 posts

642

print(f"User: {post.get('username', 'Anonymous')}")

643

print(f"Content: {post.get('content', '')[:100]}...")

644

print(f"Likes: {post.get('likes', 0)}")

645

print("-" * 30)

646

647

# Get home feed content

648

home_feed = paper_wb.get_social_home('trending', num=20)

649

print(f"Home feed has {len(home_feed)} trending items")

650

```