strategy.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. from typing import Mapping
  2. from okx_codex_trader.models import Candle, TradeSignal
  3. def simple_moving_average(candles: list[Candle], window: int) -> list[float | None]:
  4. averages: list[float | None] = []
  5. running_total = 0.0
  6. for index, candle in enumerate(candles):
  7. running_total += candle.close
  8. if index >= window:
  9. running_total -= candles[index - window].close
  10. if index + 1 < window:
  11. averages.append(None)
  12. continue
  13. averages.append(running_total / window)
  14. return averages
  15. def validate_signal(payload: Mapping[str, object]) -> TradeSignal:
  16. required_keys = {
  17. "action",
  18. "confidence",
  19. "leverage",
  20. "entry_price",
  21. "take_profit_price",
  22. "stop_loss_price",
  23. "reason",
  24. }
  25. if set(payload) != required_keys:
  26. raise ValueError("signal shape is invalid")
  27. action = payload["action"]
  28. if action not in {"long", "short", "flat"}:
  29. raise ValueError("signal action is invalid")
  30. confidence = payload["confidence"]
  31. if isinstance(confidence, bool):
  32. raise ValueError("signal confidence is invalid")
  33. if not isinstance(confidence, int | float) or not 0 <= float(confidence) <= 1:
  34. raise ValueError("signal confidence is invalid")
  35. leverage = payload["leverage"]
  36. if isinstance(leverage, bool):
  37. raise ValueError("signal leverage is invalid")
  38. if not isinstance(leverage, int) or not 1 <= leverage <= 3:
  39. raise ValueError("signal leverage is invalid")
  40. entry_price = payload["entry_price"]
  41. if entry_price is not None:
  42. if isinstance(entry_price, bool):
  43. raise ValueError("signal entry_price is invalid")
  44. if not isinstance(entry_price, int | float):
  45. raise ValueError("signal entry_price is invalid")
  46. entry_price = float(entry_price)
  47. take_profit_price = payload["take_profit_price"]
  48. if take_profit_price is not None:
  49. if isinstance(take_profit_price, bool):
  50. raise ValueError("signal take_profit_price is invalid")
  51. if not isinstance(take_profit_price, int | float):
  52. raise ValueError("signal take_profit_price is invalid")
  53. take_profit_price = float(take_profit_price)
  54. stop_loss_price = payload["stop_loss_price"]
  55. if stop_loss_price is not None:
  56. if isinstance(stop_loss_price, bool):
  57. raise ValueError("signal stop_loss_price is invalid")
  58. if not isinstance(stop_loss_price, int | float):
  59. raise ValueError("signal stop_loss_price is invalid")
  60. stop_loss_price = float(stop_loss_price)
  61. reason = payload["reason"]
  62. if not isinstance(reason, str) or not reason:
  63. raise ValueError("signal reason is invalid")
  64. return TradeSignal(
  65. action=action,
  66. confidence=float(confidence),
  67. leverage=leverage,
  68. entry_price=entry_price,
  69. take_profit_price=take_profit_price,
  70. stop_loss_price=stop_loss_price,
  71. reason=reason,
  72. )