Name | pysailfish JSON |
Version |
1.18.0
JSON |
| download |
home_page | |
Summary | |
upload_time | 2023-12-02 06:07:32 |
maintainer | |
docs_url | None |
author | SulfredLee |
requires_python | >=3.8,<4.0 |
license | |
keywords |
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
## pysailfish
### Example EA --- simple client
```python
from pysailfish.internal.MT_EA.MT4_EA import MT4_EA
class MT4DemoEA(MT4_EA):
def __init__(self):
super().__init__()
# override
def _OnInit(self) -> int:
self._logger.info(self._user_inputs)
self._logger.info("Here")
return 0
# override
def _OnDeinit(self, reason: int) -> None:
self._logger.info(f"Here reason: {reason}")
return None
# override
def _OnTick(self) -> None:
self._logger.info("Here")
return None
# override
def _OnTimer(self) -> None:
return None
# override
def _OnTester(self) -> float:
self._logger.info("Here")
return 0.0
# override
def _OnChartEvent(self
, id: int
, lparam: int
, dparam: float
, sparam: str) -> None:
self._logger.info(f"Here id: {id} lparam: {lparam} dparam: {dparam} sparam: {sparam}")
return None
def main() -> None:
ea = MT4DemoEA()
ea.InitComponent(server_ip="127.0.0.1"
, server_port=23456
, ea_name="MT4DemoEA")
ea.StartEA()
if __name__ == "__main__":
main()
```
### Example EA --- Moving Average EA
```python
from datetime import datetime
import pysailfish.internal.MT_EA.mt4_const as mc
from pysailfish.internal.MT_EA.MT4_EA import MT4_EA
class MA_EA(MT4_EA):
def __init__(self):
super().__init__()
# override
def _OnInit(self) -> int:
self._logger.info(self._user_inputs)
self._logger.info("Here")
return 0
# override
def _OnDeinit(self, reason: int) -> None:
self._logger.info(f"Here reason: {reason}")
return None
# override
def _OnTick(self) -> None:
vv = self.iADX(symbol=self._pv.symbol
, timeframe=mc.PERIOD_CURRENT
, period=self._user_inputs["MovingPeriod"]
, applied_price=mc.PRICE_CLOSE
, mode=mc.MODE_MAIN
, shift=0)
# self._logger.info(f"Here {self._pv.symbol} {self._pv.time[0]}")
# --- check for history and trading
if self._pv.bars < 100 or self._pv.is_trade_allowed == False:
return
# --- calculate open orders by current symbol
if self.__calculate_current_orders(self._pv.symbol) == 0:
self.__check_for_open()
else:
self.__check_for_close()
return None
# override
def _OnTimer(self) -> None:
return None
# override
def _OnTester(self) -> float:
self._logger.info("Here")
return 0.0
# override
def _OnChartEvent(self
, id: int
, lparam: int
, dparam: float
, sparam: str) -> None:
self._logger.info(f"Here id: {id} lparam: {lparam} dparam: {dparam} sparam: {sparam}")
return None
def __check_for_close(self) -> None:
ma: float = 0
#--- go trading only for first tiks of new bar
if self._pv.volume[0] > 1:
return None
#--- get Moving Average
ma = self.iMA(symbol=self._pv.symbol
, timeframe=mc.PERIOD_CURRENT
, ma_period=self._user_inputs["MovingPeriod"]
, ma_shift=self._user_inputs["MovingShift"]
, ma_method=mc.MODE_SMA
, applied_price=mc.PRICE_CLOSE
, shift=0)
#---
for i in range(self.OrdersTotal()):
if self.OrderSelect(index=i, select=mc.SELECT_BY_POS, pool=mc.MODE_TRADES) == False:
break
if self.OrderMagicNumber() != self._pv.magic_num or self.OrderSymbol() != self._pv.symbol:
continue
#--- check order type
if self.OrderType() == mc.OP_BUY:
if self._pv.open[1] > ma and self._pv.close[1] < ma:
if not self.OrderClose(ticket=self.OrderTicket(), lots=self.OrderLots(), price=self._pv.bid, slippage=3, arrow_color=mc.clrWhite):
self._logger.error(f"OrderClose error {self.GetLastError()}")
break
if self.OrderType() == mc.OP_SELL:
if self._pv.open[1] < ma and self._pv.close[1] > ma:
if not self.OrderClose(ticket=self.OrderTicket(), lots=self.OrderLots(), price=self._pv.ask, slippage=3, arrow_color=mc.clrWhite):
self._logger.error(f"OrderClose error {self.GetLastError()}");
break
def __lots_optimized(self) -> float:
lot: float = float(self._user_inputs["Lots"])
maximum_risk: float = float(self._user_inputs["MaximumRisk"])
decrease_factor: float = float(self._user_inputs["DecreaseFactor"])
orders: int = self.OrdersHistoryTotal() # history orders total
losses: int = 0 # number of losses orders without a break
#--- select lot size
lot = self.NormalizeDouble(value=(self.AccountFreeMargin() * maximum_risk / 1000.0), digits=1);
#--- calcuulate number of losses orders without a break
if decrease_factor > 0:
for i in reversed(range(orders)):
if self.OrderSelect(index=i, select=mc.SELECT_BY_POS, pool=mc.MODE_HISTORY) == False:
self._logger.error("Error in history")
break
if self.OrderSymbol() != self._pv.symbol or self.OrderType() > mc.OP_SELL:
continue
#---
if self.OrderProfit() > 0:
break
if self.OrderProfit() < 0:
losses += 1
if losses > 1:
lot = self.NormalizeDouble(value=(lot - lot * losses / decrease_factor), digits=1)
#--- return lot size
if lot < 0.1:
lot = 0.1
return lot
def __check_for_open(self) -> None:
ma: float = 0
res: int = 0
#--- go trading only for first tiks of new bar
if self._pv.volume[0] > 1:
return None
#--- get Moving Average
ma = self.iMA(symbol=self._pv.symbol
, timeframe=mc.PERIOD_CURRENT
, ma_period=self._user_inputs["MovingPeriod"]
, ma_shift=self._user_inputs["MovingShift"]
, ma_method=mc.MODE_SMA
, applied_price=mc.PRICE_CLOSE
, shift=0)
#--- sell conditions
if self._pv.open[1] > ma and self._pv.close[1] < ma:
res = self.OrderSend(symbol=self._pv.symbol
, cmd=mc.OP_SELL
, volume=self.__lots_optimized()
, price=self._pv.bid
, slippage=3
, stoploss=0
, takeprofit=0
, comment=""
, magic=self._pv.magic_num
, expiration=datetime(1970, 1, 1, 0, 0, 0)
, arrow_color=mc.clrRed)
return None
#--- buy conditions
if self._pv.open[1] < ma and self._pv.close[1] > ma:
res = self.OrderSend(symbol=self._pv.symbol
, cmd=mc.OP_BUY
, volume=self.__lots_optimized()
, price=self._pv.ask
, slippage=3
, stoploss=0
, takeprofit=0
, comment=""
, magic=self._pv.magic_num
, expiration=datetime(1970, 1, 1, 0, 0, 0)
, arrow_color=mc.clrBlue)
return None
def __calculate_current_orders(self, symbol: str) -> int:
buys: int = 0
sells: int = 0
# ---
for i in range(self.OrdersTotal()):
if self._tf.order_select(index=i, select=mc.SELECT_BY_POS, pool=mc.MODE_TRADES) == False:
break
if self.OrderSymbol() == self._pv.symbol and self.OrderMagicNumber() == self._pv.magic_num:
if self.OrderType() == mc.OP_BUY:
buys += 1
if self.OrderType() == mc.OP_SELL:
sells += 1
# --- return orders volume
if buys > 0:
return buys
else:
return -sells
def main() -> None:
ea = MA_EA()
ea.InitComponent(server_ip="127.0.0.1"
, server_port=23456
, ea_name="MA_EA")
ea.StartEA()
if __name__ == "__main__":
main()
```
### How to publish to pypi
```bash
# set up pypi token
$ poetry config pypi-token.pypi my-token
# build the project
$ poetry build
# publish the project
$ poetry publish
# DONE
```
Raw data
{
"_id": null,
"home_page": "",
"name": "pysailfish",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8,<4.0",
"maintainer_email": "",
"keywords": "",
"author": "SulfredLee",
"author_email": "sflee1112@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/5f/e1/cdf62ae0c64b4df2304a4a15393e281f1f65e1e10a3658b119eac1ef326f/pysailfish-1.18.0.tar.gz",
"platform": null,
"description": "\n## pysailfish\n\n### Example EA --- simple client\n```python\nfrom pysailfish.internal.MT_EA.MT4_EA import MT4_EA\n\nclass MT4DemoEA(MT4_EA):\n def __init__(self):\n super().__init__()\n\n # override\n def _OnInit(self) -> int:\n self._logger.info(self._user_inputs)\n self._logger.info(\"Here\")\n return 0\n\n # override\n def _OnDeinit(self, reason: int) -> None:\n self._logger.info(f\"Here reason: {reason}\")\n return None\n\n # override\n def _OnTick(self) -> None:\n self._logger.info(\"Here\")\n return None\n\n # override\n def _OnTimer(self) -> None:\n return None\n\n # override\n def _OnTester(self) -> float:\n self._logger.info(\"Here\")\n return 0.0\n\n # override\n def _OnChartEvent(self\n , id: int\n , lparam: int\n , dparam: float\n , sparam: str) -> None:\n self._logger.info(f\"Here id: {id} lparam: {lparam} dparam: {dparam} sparam: {sparam}\")\n return None\n\ndef main() -> None:\n ea = MT4DemoEA()\n ea.InitComponent(server_ip=\"127.0.0.1\"\n , server_port=23456\n , ea_name=\"MT4DemoEA\")\n ea.StartEA()\n\nif __name__ == \"__main__\":\n main()\n```\n\n### Example EA --- Moving Average EA\n```python\nfrom datetime import datetime\n\nimport pysailfish.internal.MT_EA.mt4_const as mc\nfrom pysailfish.internal.MT_EA.MT4_EA import MT4_EA\n\nclass MA_EA(MT4_EA):\n def __init__(self):\n super().__init__()\n\n # override\n def _OnInit(self) -> int:\n self._logger.info(self._user_inputs)\n self._logger.info(\"Here\")\n return 0\n\n # override\n def _OnDeinit(self, reason: int) -> None:\n self._logger.info(f\"Here reason: {reason}\")\n return None\n\n # override\n def _OnTick(self) -> None:\n vv = self.iADX(symbol=self._pv.symbol\n , timeframe=mc.PERIOD_CURRENT\n , period=self._user_inputs[\"MovingPeriod\"]\n , applied_price=mc.PRICE_CLOSE\n , mode=mc.MODE_MAIN\n , shift=0)\n # self._logger.info(f\"Here {self._pv.symbol} {self._pv.time[0]}\")\n # --- check for history and trading\n if self._pv.bars < 100 or self._pv.is_trade_allowed == False:\n return\n\n # --- calculate open orders by current symbol\n if self.__calculate_current_orders(self._pv.symbol) == 0:\n self.__check_for_open()\n else:\n self.__check_for_close()\n return None\n\n # override\n def _OnTimer(self) -> None:\n return None\n\n # override\n def _OnTester(self) -> float:\n self._logger.info(\"Here\")\n return 0.0\n\n # override\n def _OnChartEvent(self\n , id: int\n , lparam: int\n , dparam: float\n , sparam: str) -> None:\n self._logger.info(f\"Here id: {id} lparam: {lparam} dparam: {dparam} sparam: {sparam}\")\n return None\n\n def __check_for_close(self) -> None:\n ma: float = 0\n #--- go trading only for first tiks of new bar\n if self._pv.volume[0] > 1:\n return None\n #--- get Moving Average\n ma = self.iMA(symbol=self._pv.symbol\n , timeframe=mc.PERIOD_CURRENT\n , ma_period=self._user_inputs[\"MovingPeriod\"]\n , ma_shift=self._user_inputs[\"MovingShift\"]\n , ma_method=mc.MODE_SMA\n , applied_price=mc.PRICE_CLOSE\n , shift=0)\n #---\n for i in range(self.OrdersTotal()):\n if self.OrderSelect(index=i, select=mc.SELECT_BY_POS, pool=mc.MODE_TRADES) == False:\n break\n if self.OrderMagicNumber() != self._pv.magic_num or self.OrderSymbol() != self._pv.symbol:\n continue\n #--- check order type\n if self.OrderType() == mc.OP_BUY:\n if self._pv.open[1] > ma and self._pv.close[1] < ma:\n if not self.OrderClose(ticket=self.OrderTicket(), lots=self.OrderLots(), price=self._pv.bid, slippage=3, arrow_color=mc.clrWhite):\n self._logger.error(f\"OrderClose error {self.GetLastError()}\")\n break\n if self.OrderType() == mc.OP_SELL:\n if self._pv.open[1] < ma and self._pv.close[1] > ma:\n if not self.OrderClose(ticket=self.OrderTicket(), lots=self.OrderLots(), price=self._pv.ask, slippage=3, arrow_color=mc.clrWhite):\n self._logger.error(f\"OrderClose error {self.GetLastError()}\");\n break\n\n def __lots_optimized(self) -> float:\n lot: float = float(self._user_inputs[\"Lots\"])\n maximum_risk: float = float(self._user_inputs[\"MaximumRisk\"])\n decrease_factor: float = float(self._user_inputs[\"DecreaseFactor\"])\n orders: int = self.OrdersHistoryTotal() # history orders total\n losses: int = 0 # number of losses orders without a break\n #--- select lot size\n lot = self.NormalizeDouble(value=(self.AccountFreeMargin() * maximum_risk / 1000.0), digits=1);\n #--- calcuulate number of losses orders without a break\n if decrease_factor > 0:\n for i in reversed(range(orders)):\n if self.OrderSelect(index=i, select=mc.SELECT_BY_POS, pool=mc.MODE_HISTORY) == False:\n self._logger.error(\"Error in history\")\n break\n if self.OrderSymbol() != self._pv.symbol or self.OrderType() > mc.OP_SELL:\n continue\n #---\n if self.OrderProfit() > 0:\n break\n if self.OrderProfit() < 0:\n losses += 1\n if losses > 1:\n lot = self.NormalizeDouble(value=(lot - lot * losses / decrease_factor), digits=1)\n #--- return lot size\n if lot < 0.1:\n lot = 0.1\n return lot\n\n def __check_for_open(self) -> None:\n ma: float = 0\n res: int = 0\n #--- go trading only for first tiks of new bar\n if self._pv.volume[0] > 1:\n return None\n #--- get Moving Average\n ma = self.iMA(symbol=self._pv.symbol\n , timeframe=mc.PERIOD_CURRENT\n , ma_period=self._user_inputs[\"MovingPeriod\"]\n , ma_shift=self._user_inputs[\"MovingShift\"]\n , ma_method=mc.MODE_SMA\n , applied_price=mc.PRICE_CLOSE\n , shift=0)\n #--- sell conditions\n if self._pv.open[1] > ma and self._pv.close[1] < ma:\n res = self.OrderSend(symbol=self._pv.symbol\n , cmd=mc.OP_SELL\n , volume=self.__lots_optimized()\n , price=self._pv.bid\n , slippage=3\n , stoploss=0\n , takeprofit=0\n , comment=\"\"\n , magic=self._pv.magic_num\n , expiration=datetime(1970, 1, 1, 0, 0, 0)\n , arrow_color=mc.clrRed)\n return None\n #--- buy conditions\n if self._pv.open[1] < ma and self._pv.close[1] > ma:\n res = self.OrderSend(symbol=self._pv.symbol\n , cmd=mc.OP_BUY\n , volume=self.__lots_optimized()\n , price=self._pv.ask\n , slippage=3\n , stoploss=0\n , takeprofit=0\n , comment=\"\"\n , magic=self._pv.magic_num\n , expiration=datetime(1970, 1, 1, 0, 0, 0)\n , arrow_color=mc.clrBlue)\n return None\n\n def __calculate_current_orders(self, symbol: str) -> int:\n buys: int = 0\n sells: int = 0\n # ---\n for i in range(self.OrdersTotal()):\n if self._tf.order_select(index=i, select=mc.SELECT_BY_POS, pool=mc.MODE_TRADES) == False:\n break\n if self.OrderSymbol() == self._pv.symbol and self.OrderMagicNumber() == self._pv.magic_num:\n if self.OrderType() == mc.OP_BUY:\n buys += 1\n if self.OrderType() == mc.OP_SELL:\n sells += 1\n # --- return orders volume\n if buys > 0:\n return buys\n else:\n return -sells\n\ndef main() -> None:\n ea = MA_EA()\n ea.InitComponent(server_ip=\"127.0.0.1\"\n , server_port=23456\n , ea_name=\"MA_EA\")\n ea.StartEA()\n\nif __name__ == \"__main__\":\n main()\n```\n\n### How to publish to pypi\n```bash\n# set up pypi token\n$ poetry config pypi-token.pypi my-token\n\n# build the project\n$ poetry build\n\n# publish the project\n$ poetry publish\n\n# DONE\n```\n",
"bugtrack_url": null,
"license": "",
"summary": "",
"version": "1.18.0",
"project_urls": null,
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "be83fdf23266ca13a4766872eb0d5088629db9e766fe564450df4c434e321011",
"md5": "cc8748d4b3e3f4a4e197423697aecd16",
"sha256": "fb4029b3138ebe9516a15bb4a7923be369329d4270765b00250a3018877c7971"
},
"downloads": -1,
"filename": "pysailfish-1.18.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "cc8748d4b3e3f4a4e197423697aecd16",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8,<4.0",
"size": 48239,
"upload_time": "2023-12-02T06:07:28",
"upload_time_iso_8601": "2023-12-02T06:07:28.467477Z",
"url": "https://files.pythonhosted.org/packages/be/83/fdf23266ca13a4766872eb0d5088629db9e766fe564450df4c434e321011/pysailfish-1.18.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "5fe1cdf62ae0c64b4df2304a4a15393e281f1f65e1e10a3658b119eac1ef326f",
"md5": "7a7fe046aafbcdec3d1d7cad91425c66",
"sha256": "60c321a234e9beb60270b10e61b77f793b570909d43f74b454f007dbad91adb6"
},
"downloads": -1,
"filename": "pysailfish-1.18.0.tar.gz",
"has_sig": false,
"md5_digest": "7a7fe046aafbcdec3d1d7cad91425c66",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8,<4.0",
"size": 33633,
"upload_time": "2023-12-02T06:07:32",
"upload_time_iso_8601": "2023-12-02T06:07:32.980253Z",
"url": "https://files.pythonhosted.org/packages/5f/e1/cdf62ae0c64b4df2304a4a15393e281f1f65e1e10a3658b119eac1ef326f/pysailfish-1.18.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-02 06:07:32",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "pysailfish"
}