• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

freqtrade / freqtrade / 16639537506

04 Jul 2025 05:26PM UTC coverage: 94.234% (-0.02%) from 94.256%
16639537506

push

github

xmatthias
chore: Update dockerfile syntax

22146 of 23501 relevant lines covered (94.23%)

0.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.8
/freqtrade/rpc/api_server/api_schemas.py
1
from datetime import date, datetime
1✔
2
from typing import Any
1✔
3

4
from pydantic import AwareDatetime, BaseModel, RootModel, SerializeAsAny, model_validator
1✔
5

6
from freqtrade.constants import DL_DATA_TIMEFRAMES, IntOrInf
1✔
7
from freqtrade.enums import MarginMode, OrderTypeValues, SignalDirection, TradingMode
1✔
8
from freqtrade.ft_types import AnnotationType, ValidExchangesType
1✔
9
from freqtrade.rpc.api_server.webserver_bgwork import ProgressTask
1✔
10

11

12
class ExchangeModePayloadMixin(BaseModel):
1✔
13
    trading_mode: TradingMode | None = None
1✔
14
    margin_mode: MarginMode | None = None
1✔
15
    exchange: str | None = None
1✔
16

17

18
class Ping(BaseModel):
1✔
19
    status: str
1✔
20

21

22
class AccessToken(BaseModel):
1✔
23
    access_token: str
1✔
24

25

26
class AccessAndRefreshToken(AccessToken):
1✔
27
    refresh_token: str
1✔
28

29

30
class Version(BaseModel):
1✔
31
    version: str
1✔
32

33

34
class StatusMsg(BaseModel):
1✔
35
    status: str
1✔
36

37

38
class BgJobStarted(StatusMsg):
1✔
39
    job_id: str
1✔
40

41

42
class BackgroundTaskStatus(BaseModel):
1✔
43
    job_id: str
1✔
44
    job_category: str
1✔
45
    status: str
1✔
46
    running: bool
1✔
47
    progress: float | None = None
1✔
48
    progress_tasks: dict[str, ProgressTask] | None = None
1✔
49
    error: str | None = None
1✔
50

51

52
class BackgroundTaskResult(BaseModel):
1✔
53
    error: str | None = None
1✔
54
    status: str
1✔
55

56

57
class ResultMsg(BaseModel):
1✔
58
    result: str
1✔
59

60

61
class Balance(BaseModel):
1✔
62
    currency: str
1✔
63
    free: float
1✔
64
    balance: float
1✔
65
    used: float
1✔
66
    bot_owned: float | None = None
1✔
67
    est_stake: float
1✔
68
    est_stake_bot: float | None = None
1✔
69
    stake: str
1✔
70
    # Starting with 2.x
71
    side: str
1✔
72
    is_position: bool
1✔
73
    position: float
1✔
74
    is_bot_managed: bool
1✔
75

76

77
class Balances(BaseModel):
1✔
78
    currencies: list[Balance]
1✔
79
    total: float
1✔
80
    total_bot: float
1✔
81
    symbol: str
1✔
82
    value: float
1✔
83
    value_bot: float
1✔
84
    stake: str
1✔
85
    note: str
1✔
86
    starting_capital: float
1✔
87
    starting_capital_ratio: float
1✔
88
    starting_capital_pct: float
1✔
89
    starting_capital_fiat: float
1✔
90
    starting_capital_fiat_ratio: float
1✔
91
    starting_capital_fiat_pct: float
1✔
92

93

94
class Count(BaseModel):
1✔
95
    current: int
1✔
96
    max: int
1✔
97
    total_stake: float
1✔
98

99

100
class __BaseStatsModel(BaseModel):
1✔
101
    profit_ratio: float
1✔
102
    profit_pct: float
1✔
103
    profit_abs: float
1✔
104
    count: int
1✔
105

106

107
class Entry(__BaseStatsModel):
1✔
108
    enter_tag: str
1✔
109

110

111
class Exit(__BaseStatsModel):
1✔
112
    exit_reason: str
1✔
113

114

115
class MixTag(__BaseStatsModel):
1✔
116
    mix_tag: str
1✔
117

118

119
class PerformanceEntry(__BaseStatsModel):
1✔
120
    pair: str
1✔
121
    profit: float
1✔
122

123

124
class Profit(BaseModel):
1✔
125
    profit_closed_coin: float
1✔
126
    profit_closed_percent_mean: float
1✔
127
    profit_closed_ratio_mean: float
1✔
128
    profit_closed_percent_sum: float
1✔
129
    profit_closed_ratio_sum: float
1✔
130
    profit_closed_percent: float
1✔
131
    profit_closed_ratio: float
1✔
132
    profit_closed_fiat: float
1✔
133
    profit_all_coin: float
1✔
134
    profit_all_percent_mean: float
1✔
135
    profit_all_ratio_mean: float
1✔
136
    profit_all_percent_sum: float
1✔
137
    profit_all_ratio_sum: float
1✔
138
    profit_all_percent: float
1✔
139
    profit_all_ratio: float
1✔
140
    profit_all_fiat: float
1✔
141
    trade_count: int
1✔
142
    closed_trade_count: int
1✔
143
    first_trade_date: str
1✔
144
    first_trade_humanized: str
1✔
145
    first_trade_timestamp: int
1✔
146
    latest_trade_date: str
1✔
147
    latest_trade_humanized: str
1✔
148
    latest_trade_timestamp: int
1✔
149
    avg_duration: str
1✔
150
    best_pair: str
1✔
151
    best_rate: float
1✔
152
    best_pair_profit_ratio: float
1✔
153
    best_pair_profit_abs: float
1✔
154
    winning_trades: int
1✔
155
    losing_trades: int
1✔
156
    profit_factor: float
1✔
157
    winrate: float
1✔
158
    expectancy: float
1✔
159
    expectancy_ratio: float
1✔
160
    max_drawdown: float
1✔
161
    max_drawdown_abs: float
1✔
162
    max_drawdown_start: str
1✔
163
    max_drawdown_start_timestamp: int
1✔
164
    max_drawdown_end: str
1✔
165
    max_drawdown_end_timestamp: int
1✔
166
    trading_volume: float | None = None
1✔
167
    bot_start_timestamp: int
1✔
168
    bot_start_date: str
1✔
169

170

171
class SellReason(BaseModel):
1✔
172
    wins: int
1✔
173
    losses: int
1✔
174
    draws: int
1✔
175

176

177
class Stats(BaseModel):
1✔
178
    exit_reasons: dict[str, SellReason]
1✔
179
    durations: dict[str, float | None]
1✔
180

181

182
class DailyWeeklyMonthlyRecord(BaseModel):
1✔
183
    date: date
1✔
184
    abs_profit: float
1✔
185
    rel_profit: float
1✔
186
    starting_balance: float
1✔
187
    fiat_value: float
1✔
188
    trade_count: int
1✔
189

190

191
class DailyWeeklyMonthly(BaseModel):
1✔
192
    data: list[DailyWeeklyMonthlyRecord]
1✔
193
    fiat_display_currency: str
1✔
194
    stake_currency: str
1✔
195

196

197
class UnfilledTimeout(BaseModel):
1✔
198
    entry: int | None = None
1✔
199
    exit: int | None = None
1✔
200
    unit: str | None = None
1✔
201
    exit_timeout_count: int | None = None
1✔
202

203

204
class OrderTypes(BaseModel):
1✔
205
    entry: OrderTypeValues
1✔
206
    exit: OrderTypeValues
1✔
207
    emergency_exit: OrderTypeValues | None = None
1✔
208
    force_exit: OrderTypeValues | None = None
1✔
209
    force_entry: OrderTypeValues | None = None
1✔
210
    stoploss: OrderTypeValues
1✔
211
    stoploss_on_exchange: bool
1✔
212
    stoploss_on_exchange_interval: int | None = None
1✔
213

214

215
class ShowConfig(BaseModel):
1✔
216
    version: str
1✔
217
    strategy_version: str | None = None
1✔
218
    api_version: float
1✔
219
    dry_run: bool
1✔
220
    trading_mode: str
1✔
221
    short_allowed: bool
1✔
222
    stake_currency: str
1✔
223
    stake_amount: str
1✔
224
    available_capital: float | None = None
1✔
225
    stake_currency_decimals: int
1✔
226
    max_open_trades: IntOrInf
1✔
227
    minimal_roi: dict[str, Any]
1✔
228
    stoploss: float | None = None
1✔
229
    stoploss_on_exchange: bool
1✔
230
    trailing_stop: bool | None = None
1✔
231
    trailing_stop_positive: float | None = None
1✔
232
    trailing_stop_positive_offset: float | None = None
1✔
233
    trailing_only_offset_is_reached: bool | None = None
1✔
234
    unfilledtimeout: UnfilledTimeout | None = None  # Empty in webserver mode
1✔
235
    order_types: OrderTypes | None = None
1✔
236
    use_custom_stoploss: bool | None = None
1✔
237
    timeframe: str | None = None
1✔
238
    timeframe_ms: int
1✔
239
    timeframe_min: int
1✔
240
    exchange: str
1✔
241
    strategy: str | None = None
1✔
242
    force_entry_enable: bool
1✔
243
    exit_pricing: dict[str, Any]
1✔
244
    entry_pricing: dict[str, Any]
1✔
245
    bot_name: str
1✔
246
    state: str
1✔
247
    runmode: str
1✔
248
    position_adjustment_enable: bool
1✔
249
    max_entry_position_adjustment: int
1✔
250

251

252
class OrderSchema(BaseModel):
1✔
253
    pair: str
1✔
254
    order_id: str
1✔
255
    status: str
1✔
256
    remaining: float | None = None
1✔
257
    amount: float
1✔
258
    safe_price: float
1✔
259
    cost: float
1✔
260
    filled: float | None = None
1✔
261
    ft_order_side: str
1✔
262
    order_type: str
1✔
263
    is_open: bool
1✔
264
    order_timestamp: int | None = None
1✔
265
    order_filled_timestamp: int | None = None
1✔
266
    ft_fee_base: float | None = None
1✔
267
    ft_order_tag: str | None = None
1✔
268

269

270
class TradeSchema(BaseModel):
1✔
271
    trade_id: int
1✔
272
    pair: str
1✔
273
    base_currency: str
1✔
274
    quote_currency: str
1✔
275
    is_open: bool
1✔
276
    is_short: bool
1✔
277
    exchange: str
1✔
278
    amount: float
1✔
279
    amount_requested: float
1✔
280
    stake_amount: float
1✔
281
    max_stake_amount: float | None = None
1✔
282
    strategy: str
1✔
283
    enter_tag: str | None = None
1✔
284
    timeframe: int
1✔
285
    fee_open: float | None = None
1✔
286
    fee_open_cost: float | None = None
1✔
287
    fee_open_currency: str | None = None
1✔
288
    fee_close: float | None = None
1✔
289
    fee_close_cost: float | None = None
1✔
290
    fee_close_currency: str | None = None
1✔
291

292
    open_date: str
1✔
293
    open_timestamp: int
1✔
294
    open_fill_date: str | None
1✔
295
    open_fill_timestamp: int | None
1✔
296
    open_rate: float
1✔
297
    open_rate_requested: float | None = None
1✔
298
    open_trade_value: float
1✔
299

300
    close_date: str | None = None
1✔
301
    close_timestamp: int | None = None
1✔
302
    close_rate: float | None = None
1✔
303
    close_rate_requested: float | None = None
1✔
304

305
    close_profit: float | None = None
1✔
306
    close_profit_pct: float | None = None
1✔
307
    close_profit_abs: float | None = None
1✔
308

309
    profit_ratio: float | None = None
1✔
310
    profit_pct: float | None = None
1✔
311
    profit_abs: float | None = None
1✔
312
    profit_fiat: float | None = None
1✔
313

314
    realized_profit: float
1✔
315
    realized_profit_ratio: float | None = None
1✔
316

317
    exit_reason: str | None = None
1✔
318
    exit_order_status: str | None = None
1✔
319

320
    stop_loss_abs: float | None = None
1✔
321
    stop_loss_ratio: float | None = None
1✔
322
    stop_loss_pct: float | None = None
1✔
323
    stoploss_last_update: str | None = None
1✔
324
    stoploss_last_update_timestamp: int | None = None
1✔
325
    initial_stop_loss_abs: float | None = None
1✔
326
    initial_stop_loss_ratio: float | None = None
1✔
327
    initial_stop_loss_pct: float | None = None
1✔
328

329
    min_rate: float | None = None
1✔
330
    max_rate: float | None = None
1✔
331
    has_open_orders: bool
1✔
332
    orders: list[OrderSchema]
1✔
333

334
    leverage: float | None = None
1✔
335
    interest_rate: float | None = None
1✔
336
    liquidation_price: float | None = None
1✔
337
    funding_fees: float | None = None
1✔
338
    trading_mode: TradingMode | None = None
1✔
339

340
    amount_precision: float | None = None
1✔
341
    price_precision: float | None = None
1✔
342
    precision_mode: int | None = None
1✔
343

344

345
class OpenTradeSchema(TradeSchema):
1✔
346
    stoploss_current_dist: float | None = None
1✔
347
    stoploss_current_dist_pct: float | None = None
1✔
348
    stoploss_current_dist_ratio: float | None = None
1✔
349
    stoploss_entry_dist: float | None = None
1✔
350
    stoploss_entry_dist_ratio: float | None = None
1✔
351
    current_rate: float
1✔
352
    total_profit_abs: float
1✔
353
    total_profit_fiat: float | None = None
1✔
354
    total_profit_ratio: float | None = None
1✔
355

356

357
class TradeResponse(BaseModel):
1✔
358
    trades: list[TradeSchema]
1✔
359
    trades_count: int
1✔
360
    offset: int
1✔
361
    total_trades: int
1✔
362

363

364
ForceEnterResponse = RootModel[TradeSchema | StatusMsg]
1✔
365

366

367
class LockModel(BaseModel):
1✔
368
    id: int
1✔
369
    active: bool
1✔
370
    lock_end_time: str
1✔
371
    lock_end_timestamp: int
1✔
372
    lock_time: str
1✔
373
    lock_timestamp: int
1✔
374
    pair: str
1✔
375
    side: str
1✔
376
    reason: str | None = None
1✔
377

378

379
class Locks(BaseModel):
1✔
380
    lock_count: int
1✔
381
    locks: list[LockModel]
1✔
382

383

384
class LocksPayload(BaseModel):
1✔
385
    pair: str
1✔
386
    side: str = "*"  # Default to both sides
1✔
387
    until: AwareDatetime
1✔
388
    reason: str | None = None
1✔
389

390

391
class DeleteLockRequest(BaseModel):
1✔
392
    pair: str | None = None
1✔
393
    lockid: int | None = None
1✔
394

395

396
class Logs(BaseModel):
1✔
397
    log_count: int
1✔
398
    logs: list[list]
1✔
399

400

401
class ForceEnterPayload(BaseModel):
1✔
402
    pair: str
1✔
403
    side: SignalDirection = SignalDirection.LONG
1✔
404
    price: float | None = None
1✔
405
    ordertype: OrderTypeValues | None = None
1✔
406
    stakeamount: float | None = None
1✔
407
    entry_tag: str | None = None
1✔
408
    leverage: float | None = None
1✔
409

410

411
class ForceExitPayload(BaseModel):
1✔
412
    tradeid: str | int
1✔
413
    ordertype: OrderTypeValues | None = None
1✔
414
    amount: float | None = None
1✔
415

416

417
class BlacklistPayload(BaseModel):
1✔
418
    blacklist: list[str]
1✔
419

420

421
class BlacklistResponse(BaseModel):
1✔
422
    blacklist: list[str]
1✔
423
    blacklist_expanded: list[str]
1✔
424
    errors: dict
1✔
425
    length: int
1✔
426
    method: list[str]
1✔
427

428

429
class WhitelistResponse(BaseModel):
1✔
430
    whitelist: list[str]
1✔
431
    length: int
1✔
432
    method: list[str]
1✔
433

434

435
class WhitelistEvaluateResponse(BackgroundTaskResult):
1✔
436
    result: WhitelistResponse | None = None
1✔
437

438

439
class DeleteTrade(BaseModel):
1✔
440
    cancel_order_count: int
1✔
441
    result: str
1✔
442
    result_msg: str
1✔
443
    trade_id: int
1✔
444

445

446
class PlotConfig_(BaseModel):
1✔
447
    main_plot: dict[str, Any]
1✔
448
    subplots: dict[str, Any]
1✔
449

450

451
PlotConfig = RootModel[PlotConfig_ | dict]
1✔
452

453

454
class StrategyListResponse(BaseModel):
1✔
455
    strategies: list[str]
1✔
456

457

458
class ExchangeListResponse(BaseModel):
1✔
459
    exchanges: list[ValidExchangesType]
1✔
460

461

462
class HyperoptLoss(BaseModel):
1✔
463
    name: str
1✔
464
    description: str
1✔
465

466

467
class HyperoptLossListResponse(BaseModel):
1✔
468
    loss_functions: list[HyperoptLoss]
1✔
469

470

471
class PairListResponse(BaseModel):
1✔
472
    name: str
1✔
473
    description: str
1✔
474
    is_pairlist_generator: bool
1✔
475
    params: dict[str, Any]
1✔
476

477

478
class PairListsResponse(BaseModel):
1✔
479
    pairlists: list[PairListResponse]
1✔
480

481

482
class PairListsPayload(ExchangeModePayloadMixin, BaseModel):
1✔
483
    pairlists: list[dict[str, Any]]
1✔
484
    blacklist: list[str]
1✔
485
    stake_currency: str
1✔
486

487

488
class DownloadDataPayload(ExchangeModePayloadMixin, BaseModel):
1✔
489
    pairs: list[str]
1✔
490
    timeframes: list[str] | None = DL_DATA_TIMEFRAMES
1✔
491
    days: int | None = None
1✔
492
    timerange: str | None = None
1✔
493
    erase: bool = False
1✔
494
    download_trades: bool = False
1✔
495

496
    @model_validator(mode="before")
1✔
497
    def check_mutually_exclusive(cls, values):
1✔
498
        timeframes, days = values.get("timerange"), values.get("days")
1✔
499
        if timeframes and days:
1✔
500
            raise ValueError("Only one of timeframes or days can be provided, not both.")
×
501
        return values
1✔
502

503

504
class FreqAIModelListResponse(BaseModel):
1✔
505
    freqaimodels: list[str]
1✔
506

507

508
class StrategyResponse(BaseModel):
1✔
509
    strategy: str
1✔
510
    code: str
1✔
511
    timeframe: str | None
1✔
512

513

514
class AvailablePairs(BaseModel):
1✔
515
    length: int
1✔
516
    pairs: list[str]
1✔
517
    pair_interval: list[list[str]]
1✔
518

519

520
class PairCandlesRequest(BaseModel):
1✔
521
    pair: str
1✔
522
    timeframe: str
1✔
523
    limit: int | None = None
1✔
524
    columns: list[str] | None = None
1✔
525

526

527
class PairHistoryRequest(PairCandlesRequest, ExchangeModePayloadMixin):
1✔
528
    timerange: str
1✔
529
    strategy: str | None = None
1✔
530
    freqaimodel: str | None = None
1✔
531
    live_mode: bool = False
1✔
532

533

534
class PairHistory(BaseModel):
1✔
535
    strategy: str
1✔
536
    pair: str
1✔
537
    timeframe: str
1✔
538
    timeframe_ms: int
1✔
539
    columns: list[str]
1✔
540
    all_columns: list[str] = []
1✔
541
    data: SerializeAsAny[list[Any]]
1✔
542
    annotations: list[AnnotationType] | None = None
1✔
543
    length: int
1✔
544
    buy_signals: int
1✔
545
    sell_signals: int
1✔
546
    enter_long_signals: int
1✔
547
    exit_long_signals: int
1✔
548
    enter_short_signals: int
1✔
549
    exit_short_signals: int
1✔
550
    last_analyzed: datetime
1✔
551
    last_analyzed_ts: int
1✔
552
    data_start_ts: int
1✔
553
    data_start: str
1✔
554
    data_stop: str
1✔
555
    data_stop_ts: int
1✔
556

557

558
class BacktestFreqAIInputs(BaseModel):
1✔
559
    identifier: str
1✔
560

561

562
class BacktestRequest(BaseModel):
1✔
563
    strategy: str
1✔
564
    timeframe: str | None = None
1✔
565
    timeframe_detail: str | None = None
1✔
566
    timerange: str | None = None
1✔
567
    max_open_trades: IntOrInf | None = None
1✔
568
    stake_amount: str | float | None = None
1✔
569
    enable_protections: bool
1✔
570
    dry_run_wallet: float | None = None
1✔
571
    backtest_cache: str | None = None
1✔
572
    freqaimodel: str | None = None
1✔
573
    freqai: BacktestFreqAIInputs | None = None
1✔
574

575

576
class BacktestResponse(BaseModel):
1✔
577
    status: str
1✔
578
    running: bool
1✔
579
    status_msg: str
1✔
580
    step: str
1✔
581
    progress: float
1✔
582
    trade_count: float | None = None
1✔
583
    # TODO: Properly type backtestresult...
584
    backtest_result: dict[str, Any] | None = None
1✔
585

586

587
# TODO: This is a copy of BacktestHistoryEntryType
588
class BacktestHistoryEntry(BaseModel):
1✔
589
    filename: str
1✔
590
    strategy: str
1✔
591
    run_id: str
1✔
592
    backtest_start_time: int
1✔
593
    notes: str | None = ""
1✔
594
    backtest_start_ts: int | None = None
1✔
595
    backtest_end_ts: int | None = None
1✔
596
    timeframe: str | None = None
1✔
597
    timeframe_detail: str | None = None
1✔
598

599

600
class BacktestMetadataUpdate(BaseModel):
1✔
601
    strategy: str
1✔
602
    notes: str = ""
1✔
603

604

605
class BacktestMarketChange(BaseModel):
1✔
606
    columns: list[str]
1✔
607
    length: int
1✔
608
    data: list[list[Any]]
1✔
609

610

611
class MarketRequest(ExchangeModePayloadMixin, BaseModel):
1✔
612
    base: str | None = None
1✔
613
    quote: str | None = None
1✔
614

615

616
class MarketModel(BaseModel):
1✔
617
    symbol: str
1✔
618
    base: str
1✔
619
    quote: str
1✔
620
    spot: bool
1✔
621
    swap: bool
1✔
622

623

624
class MarketResponse(BaseModel):
1✔
625
    markets: dict[str, MarketModel]
1✔
626
    exchange_id: str
1✔
627

628

629
class SysInfo(BaseModel):
1✔
630
    cpu_pct: list[float]
1✔
631
    ram_pct: float
1✔
632

633

634
class Health(BaseModel):
1✔
635
    last_process: datetime | None = None
1✔
636
    last_process_ts: int | None = None
1✔
637
    bot_start: datetime | None = None
1✔
638
    bot_start_ts: int | None = None
1✔
639
    bot_startup: datetime | None = None
1✔
640
    bot_startup_ts: int | None = None
1✔
641

642

643
class CustomDataEntry(BaseModel):
1✔
644
    key: str
1✔
645
    type: str
1✔
646
    value: Any
1✔
647
    created_at: datetime
1✔
648
    updated_at: datetime | None = None
1✔
649

650

651
class ListCustomData(BaseModel):
1✔
652
    trade_id: int
1✔
653
    custom_data: list[CustomDataEntry]
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc