pdmt5 0.1.9__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pdmt5/trading.py CHANGED
@@ -131,6 +131,7 @@ class Mt5TradingClient(Mt5DataClient):
131
131
  self,
132
132
  symbol: str | None = None,
133
133
  order_filling_mode: Literal["IOC", "FOK", "RETURN"] = "IOC",
134
+ raise_on_error: bool = False,
134
135
  dry_run: bool = False,
135
136
  **kwargs: Any, # noqa: ANN401
136
137
  ) -> list[dict[str, Any]]:
@@ -139,6 +140,7 @@ class Mt5TradingClient(Mt5DataClient):
139
140
  Args:
140
141
  symbol: Optional symbol filter.
141
142
  order_filling_mode: Order filling mode, either "IOC", "FOK", or "RETURN".
143
+ raise_on_error: If True, raise an exception on error.
142
144
  dry_run: If True, only check the order without sending it.
143
145
  **kwargs: Additional keyword arguments for request parameters.
144
146
 
@@ -170,6 +172,7 @@ class Mt5TradingClient(Mt5DataClient):
170
172
  "position": p["ticket"],
171
173
  **kwargs,
172
174
  },
175
+ raise_on_error=raise_on_error,
173
176
  dry_run=dry_run,
174
177
  )
175
178
  for p in positions_dict
@@ -225,6 +228,7 @@ class Mt5TradingClient(Mt5DataClient):
225
228
  order_side: Literal["BUY", "SELL"],
226
229
  order_filling_mode: Literal["IOC", "FOK", "RETURN"] = "IOC",
227
230
  order_time_mode: Literal["GTC", "DAY", "SPECIFIED", "SPECIFIED_DAY"] = "GTC",
231
+ raise_on_error: bool = False,
228
232
  dry_run: bool = False,
229
233
  **kwargs: Any, # noqa: ANN401
230
234
  ) -> dict[str, Any]:
@@ -237,12 +241,14 @@ class Mt5TradingClient(Mt5DataClient):
237
241
  order_filling_mode: Order filling mode, either "IOC", "FOK", or "RETURN".
238
242
  order_time_mode: Order time mode, either "GTC", "DAY", "SPECIFIED",
239
243
  or "SPECIFIED_DAY".
244
+ raise_on_error: If True, raise an error on operation failure.
240
245
  dry_run: If True, only check the order without sending it.
241
246
  **kwargs: Additional keyword arguments for request parameters.
242
247
 
243
248
  Returns:
244
249
  Dictionary with operation result.
245
250
  """
251
+ self.logger.info("Placing market order: %s %s %s", order_side, volume, symbol)
246
252
  return self._send_or_check_order(
247
253
  request={
248
254
  "action": self.mt5.TRADE_ACTION_DEAL,
@@ -255,6 +261,7 @@ class Mt5TradingClient(Mt5DataClient):
255
261
  "type_time": getattr(self.mt5, f"ORDER_TIME_{order_time_mode.upper()}"),
256
262
  **kwargs,
257
263
  },
264
+ raise_on_error=raise_on_error,
258
265
  dry_run=dry_run,
259
266
  )
260
267
 
@@ -264,6 +271,7 @@ class Mt5TradingClient(Mt5DataClient):
264
271
  stop_loss: float | None = None,
265
272
  take_profit: float | None = None,
266
273
  tickets: list[int] | None = None,
274
+ raise_on_error: bool = False,
267
275
  dry_run: bool = False,
268
276
  **kwargs: Any, # noqa: ANN401
269
277
  ) -> list[dict[str, Any]]:
@@ -275,6 +283,7 @@ class Mt5TradingClient(Mt5DataClient):
275
283
  take_profit: New Take Profit price. If None, it will not be changed.
276
284
  tickets: List of position tickets to filter positions. If None, all open
277
285
  positions for the symbol will be considered.
286
+ raise_on_error: If True, raise an error on operation failure.
278
287
  dry_run: If True, only check the order without sending it.
279
288
  **kwargs: Additional keyword arguments for request parameters.
280
289
 
@@ -315,8 +324,17 @@ class Mt5TradingClient(Mt5DataClient):
315
324
  if sl != p["sl"] or tp != p["tp"]
316
325
  ]
317
326
  if order_requests:
327
+ self.logger.info(
328
+ "Updating SL/TP for %d positions for %s: %s/%s",
329
+ len(order_requests),
330
+ symbol,
331
+ sl,
332
+ tp,
333
+ )
318
334
  return [
319
- self._send_or_check_order(request=r, dry_run=dry_run)
335
+ self._send_or_check_order(
336
+ request=r, raise_on_error=raise_on_error, dry_run=dry_run
337
+ )
320
338
  for r in order_requests
321
339
  ]
322
340
  else:
@@ -354,15 +372,22 @@ class Mt5TradingClient(Mt5DataClient):
354
372
  else symbol_info_tick["ask"]
355
373
  ),
356
374
  )
375
+ result = {"volume": symbol_info["volume_min"], "margin": margin}
357
376
  if margin:
358
- return {"volume": symbol_info["volume_min"], "margin": margin}
377
+ self.logger.info(
378
+ "Calculated minimum %s order margin for %s: %s",
379
+ order_side,
380
+ symbol,
381
+ result,
382
+ )
359
383
  else:
360
384
  self.logger.warning(
361
- "No margin available for symbol: %s with order side: %s",
362
- symbol,
385
+ "Calculated minimum order margin to %s %s: %s",
363
386
  order_side,
387
+ symbol,
388
+ result,
364
389
  )
365
- return {"volume": symbol_info["volume_min"], "margin": 0.0}
390
+ return result
366
391
 
367
392
  def calculate_volume_by_margin(
368
393
  self,
@@ -385,12 +410,19 @@ class Mt5TradingClient(Mt5DataClient):
385
410
  order_side=order_side,
386
411
  )
387
412
  if min_order_margin_dict["margin"]:
388
- return (
413
+ result = (
389
414
  floor(margin / min_order_margin_dict["margin"])
390
415
  * min_order_margin_dict["volume"]
391
416
  )
392
417
  else:
393
- return 0.0
418
+ result = 0.0
419
+ self.logger.info(
420
+ "Calculated volume by margin to %s %s: %s",
421
+ order_side,
422
+ symbol,
423
+ result,
424
+ )
425
+ return result
394
426
 
395
427
  def calculate_spread_ratio(
396
428
  self,
@@ -405,11 +437,13 @@ class Mt5TradingClient(Mt5DataClient):
405
437
  Spread ratio as a float.
406
438
  """
407
439
  symbol_info_tick = self.symbol_info_tick_as_dict(symbol=symbol)
408
- return (
440
+ result = (
409
441
  (symbol_info_tick["ask"] - symbol_info_tick["bid"])
410
442
  / (symbol_info_tick["ask"] + symbol_info_tick["bid"])
411
443
  * 2
412
444
  )
445
+ self.logger.info("Calculated spread ratio for %s: %s", symbol, result)
446
+ return result
413
447
 
414
448
  def fetch_latest_rates_as_df(
415
449
  self,
@@ -440,13 +474,20 @@ class Mt5TradingClient(Mt5DataClient):
440
474
  )
441
475
  raise Mt5TradingError(error_message) from e
442
476
  else:
443
- return self.copy_rates_from_pos_as_df(
477
+ result = self.copy_rates_from_pos_as_df(
444
478
  symbol=symbol,
445
479
  timeframe=timeframe,
446
480
  start_pos=0,
447
481
  count=count,
448
482
  index_keys=index_keys,
449
483
  )
484
+ self.logger.info(
485
+ "Fetched latest %s rates for %s: %d rows",
486
+ granularity,
487
+ symbol,
488
+ result.shape[0],
489
+ )
490
+ return result
450
491
 
451
492
  def fetch_latest_ticks_as_df(
452
493
  self,
@@ -465,13 +506,19 @@ class Mt5TradingClient(Mt5DataClient):
465
506
  pd.DataFrame: Tick data with time index.
466
507
  """
467
508
  last_tick_time = self.symbol_info_tick_as_dict(symbol=symbol)["time"]
468
- return self.copy_ticks_range_as_df(
509
+ result = self.copy_ticks_range_as_df(
469
510
  symbol=symbol,
470
511
  date_from=(last_tick_time - timedelta(seconds=seconds)),
471
512
  date_to=(last_tick_time + timedelta(seconds=seconds)),
472
513
  flags=self.mt5.COPY_TICKS_ALL,
473
514
  index_keys=index_keys,
474
515
  )
516
+ self.logger.info(
517
+ "Fetched latest ticks for %s: %d rows",
518
+ symbol,
519
+ result.shape[0],
520
+ )
521
+ return result
475
522
 
476
523
  def collect_entry_deals_as_df(
477
524
  self,
@@ -497,14 +544,20 @@ class Mt5TradingClient(Mt5DataClient):
497
544
  index_keys=index_keys,
498
545
  )
499
546
  if deals_df.empty:
500
- return deals_df
547
+ result = deals_df
501
548
  else:
502
- return deals_df.pipe(
549
+ result = deals_df.pipe(
503
550
  lambda d: d[
504
551
  d["entry"]
505
552
  & d["type"].isin({self.mt5.DEAL_TYPE_BUY, self.mt5.DEAL_TYPE_SELL})
506
553
  ]
507
554
  )
555
+ self.logger.info(
556
+ "Collected entry deals for %s: %d rows",
557
+ symbol,
558
+ result.shape[0],
559
+ )
560
+ return result
508
561
 
509
562
  def fetch_positions_with_metrics_as_df(
510
563
  self,
@@ -520,7 +573,7 @@ class Mt5TradingClient(Mt5DataClient):
520
573
  """
521
574
  positions_df = self.positions_get_as_df(symbol=symbol)
522
575
  if positions_df.empty:
523
- return positions_df
576
+ result = positions_df
524
577
  else:
525
578
  symbol_info_tick = self.symbol_info_tick_as_dict(symbol=symbol)
526
579
  ask_margin = self.order_calc_margin(
@@ -535,7 +588,7 @@ class Mt5TradingClient(Mt5DataClient):
535
588
  volume=1,
536
589
  price=symbol_info_tick["bid"],
537
590
  )
538
- return (
591
+ result = (
539
592
  positions_df.assign(
540
593
  elapsed_seconds=lambda d: (
541
594
  symbol_info_tick["time"] - d["time"]
@@ -566,6 +619,12 @@ class Mt5TradingClient(Mt5DataClient):
566
619
  )
567
620
  .drop(columns=["buy_i", "sell_i", "sign", "underlier_increase_ratio"])
568
621
  )
622
+ self.logger.info(
623
+ "Fetched positions with metrics for %s: %d rows",
624
+ symbol,
625
+ result.shape[0],
626
+ )
627
+ return result
569
628
 
570
629
  def calculate_new_position_margin_ratio(
571
630
  self,
@@ -585,7 +644,7 @@ class Mt5TradingClient(Mt5DataClient):
585
644
  """
586
645
  account_info = self.account_info_as_dict()
587
646
  if not account_info["equity"]:
588
- return 0.0
647
+ result = 0.0
589
648
  else:
590
649
  positions_df = self.fetch_positions_with_metrics_as_df(symbol=symbol)
591
650
  current_signed_margin = (
@@ -610,6 +669,12 @@ class Mt5TradingClient(Mt5DataClient):
610
669
  )
611
670
  else:
612
671
  new_signed_margin = 0
613
- return abs(
672
+ result = abs(
614
673
  (new_signed_margin + current_signed_margin) / account_info["equity"]
615
674
  )
675
+ self.logger.info(
676
+ "Calculated new position margin ratio for %s: %s",
677
+ symbol,
678
+ result,
679
+ )
680
+ return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdmt5
3
- Version: 0.1.9
3
+ Version: 0.2.1
4
4
  Summary: Pandas-based data handler for MetaTrader 5
5
5
  Project-URL: Repository, https://github.com/dceoy/pdmt5.git
6
6
  Author-email: dceoy <dceoy@users.noreply.github.com>
@@ -15,7 +15,7 @@ Classifier: Operating System :: Microsoft :: Windows
15
15
  Classifier: Programming Language :: Python
16
16
  Classifier: Programming Language :: Python :: 3
17
17
  Classifier: Topic :: Office/Business :: Financial :: Investment
18
- Requires-Python: >=3.11
18
+ Requires-Python: <3.14,>=3.11
19
19
  Requires-Dist: metatrader5>=5.0.4424; sys_platform == 'win32'
20
20
  Requires-Dist: pandas>=2.2.2
21
21
  Requires-Dist: pydantic>=2.9.0
@@ -56,8 +56,7 @@ Pandas-based data handler for MetaTrader 5
56
56
  ### Using pip
57
57
 
58
58
  ```bash
59
- pip install -U pdmt5
60
- pip install -U MetaTrader5
59
+ pip install -U pdmt5 MetaTrader5
61
60
  ```
62
61
 
63
62
  ### Using uv
@@ -1,9 +1,9 @@
1
1
  pdmt5/__init__.py,sha256=QbSFrsi7_bgFzb-ma4DmmUjR90UvrqKMnRZq1wPRmoI,446
2
2
  pdmt5/dataframe.py,sha256=rUWtR23hrXBdBqzJhbOlIemNy73RrjSTZZJUhwoL6io,38084
3
3
  pdmt5/mt5.py,sha256=KgxHapIrh5b4L0wIOAQIjfXNZafalihbFrh9fhYHmrI,32254
4
- pdmt5/trading.py,sha256=U_6h8yR54-5_S_3hmYlAiaNT87fqeb5AK4sUWLThnf8,23433
4
+ pdmt5/trading.py,sha256=Qd4RhZprDcWTzT3JmKl8XGVq8i9hExNdPSJbCRdUx-s,25569
5
5
  pdmt5/utils.py,sha256=Ll5Q3OE5h1A_sZ_qVEnOPGniFlT6_MmHfuu0zqeLdeU,3913
6
- pdmt5-0.1.9.dist-info/METADATA,sha256=3nWXNUqiPNDE5jMs7s_IPhtNBAdnVVMvhK1D_1mCij4,16109
7
- pdmt5-0.1.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
- pdmt5-0.1.9.dist-info/licenses/LICENSE,sha256=iABrdaUGOBWLYotFupB_PGe8arV5o7rVhn-_vK6P704,1073
9
- pdmt5-0.1.9.dist-info/RECORD,,
6
+ pdmt5-0.2.1.dist-info/METADATA,sha256=OjDjumI_5kGHyEjpIg-xgZyGJSULRUJM_LQnv2IeJ-4,16100
7
+ pdmt5-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
+ pdmt5-0.2.1.dist-info/licenses/LICENSE,sha256=iABrdaUGOBWLYotFupB_PGe8arV5o7rVhn-_vK6P704,1073
9
+ pdmt5-0.2.1.dist-info/RECORD,,
File without changes