diff --git a/.gitignore b/.gitignore
index 20dee60..a2fe170 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,12 @@ v2realbot/__pycache__/config.cpython-310.pyc
.gitignore
v2realbot/enums/__pycache__/enums.cpython-310.pyc
v2realbot/common/__pycache__/model.cpython-310.pyc
+v2realbot/__pycache__/config.cpython-310.pyc
+v2realbot/backtesting/__pycache__/backtester.cpython-310.pyc
+v2realbot/common/__pycache__/model.cpython-310.pyc
+v2realbot/enums/__pycache__/enums.cpython-310.pyc
+v2realbot/indicators/__pycache__/indicators.cpython-310.pyc
+v2realbot/loader/__pycache__/aggregator.cpython-310.pyc
+v2realbot/loader/__pycache__/trade_offline_streamer.cpython-310.pyc
+v2realbot/loader/__pycache__/trade_ws_streamer.cpython-310.pyc
+v2realbot/strategy/__pycache__/base.cpython-310.pyc
diff --git a/testy/funkce.py b/testy/funkce.py
new file mode 100644
index 0000000..df52005
--- /dev/null
+++ b/testy/funkce.py
@@ -0,0 +1,18 @@
+# import os
+
+# for filename in os.listdir("v2realbot/strategyblocks/indicators/custom"):
+# print(filename)
+
+import os
+import importlib
+import v2realbot.strategyblocks.indicators.custom as ci
+
+ci.opengap.opengap()
+
+# for filename in os.listdir("v2realbot/strategyblocks/indicators/custom"):
+# if filename.endswith(".py") and filename != "__init__.py":
+# # __import__(filename[:-3])
+# #__import__(f"v2realbot.strategyblocks.indicators.custom.{filename[:-3]}")
+# __import__(f"{filename[:-3]}")
+# #importlib.import_module()
+
diff --git a/v2realbot/backtesting/backtester.py b/v2realbot/backtesting/backtester.py
index fbb4273..0fced61 100644
--- a/v2realbot/backtesting/backtester.py
+++ b/v2realbot/backtesting/backtester.py
@@ -43,7 +43,7 @@ from v2realbot.common.model import TradeUpdate, Order
#from rich import print
import threading
import asyncio
-from v2realbot.config import BT_DELAYS, DATA_DIR, BT_FILL_CONDITION_BUY_LIMIT, BT_FILL_CONDITION_SELL_LIMIT, BT_FILL_LOG_SURROUNDING_TRADES, BT_FILL_CONS_TRADES_REQUIRED
+from v2realbot.config import BT_DELAYS, DATA_DIR, BT_FILL_CONDITION_BUY_LIMIT, BT_FILL_CONDITION_SELL_LIMIT, BT_FILL_LOG_SURROUNDING_TRADES, BT_FILL_CONS_TRADES_REQUIRED,BT_FILL_PRICE_MARKET_ORDER_PREMIUM
from v2realbot.utils.utils import AttributeDict, ltp, zoneNY, trunc, count_decimals, print
from v2realbot.utils.tlog import tlog
from v2realbot.enums.enums import FillCondition
@@ -311,6 +311,12 @@ class Backtester:
#ic(i)
fill_time = i[0]
fill_price = i[1]
+ #přičteme MARKET PREMIUM z konfigurace (do budoucna mozna rozdilne pro BUY/SELL a nebo mozna z konfigurace pro dany itutl)
+ if o.side == OrderSide.BUY:
+ fill_price = fill_price + BT_FILL_PRICE_MARKET_ORDER_PREMIUM
+ elif o.side == OrderSide.SELL:
+ fill_price = fill_price - BT_FILL_PRICE_MARKET_ORDER_PREMIUM
+
print("FILL ",o.side,"MARKET at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "cena", i[1])
break
else:
diff --git a/v2realbot/common/db.py b/v2realbot/common/db.py
index 1805f74..69ea6ce 100644
--- a/v2realbot/common/db.py
+++ b/v2realbot/common/db.py
@@ -2,7 +2,7 @@ from v2realbot.config import DATA_DIR
import sqlite3
import queue
import threading
-from datetime import time
+import time
sqlite_db_file = DATA_DIR + "/v2trading.db"
# Define the connection pool
@@ -44,6 +44,7 @@ def execute_with_retry(cursor: sqlite3.Cursor, statement: str, retry_interval: i
return cursor.execute(statement)
except sqlite3.OperationalError as e:
if str(e) == "database is locked":
+ print("database retry in 1s." + str(e))
time.sleep(retry_interval)
continue
else:
diff --git a/v2realbot/common/model.py b/v2realbot/common/model.py
index 67e91f5..3df0871 100644
--- a/v2realbot/common/model.py
+++ b/v2realbot/common/model.py
@@ -24,6 +24,15 @@ from alpaca.data.enums import Exchange
# return user.id
# raise HTTPException(status_code=404, detail=f"Could not find user with id: {id}")
+class RunDay(BaseModel):
+ """
+ Helper object for batch run - carries list of days in format required by run batch manager
+ """
+ start: datetime
+ end: datetime
+ name: Optional[str] = None
+ note: Optional[str] = None
+ id: Optional[str] = None
# Define a Pydantic model for input data
class ConfigItem(BaseModel):
diff --git a/v2realbot/config.py b/v2realbot/config.py
index b5c17c9..2f56645 100644
--- a/v2realbot/config.py
+++ b/v2realbot/config.py
@@ -41,6 +41,23 @@ DATA_DIR = user_data_dir("v2realbot")
PROFILING_NEXT_ENABLED = False
PROFILING_OUTPUT_DIR = DATA_DIR
+#FILL CONFIGURATION CLASS FOR BACKTESTING
+
+#WIP
+class BT_FILL_CONF:
+ """"
+ Trida pro konfiguraci backtesting fillu pro dany symbol, pokud neexistuje tak fallback na obecny viz vyse-
+
+ MOžná udělat i separátní profil PAPER/LIVE. Nějak vymyslet profily a jejich správa.
+ """
+ def __init__(self, symbol, BT_FILL_CONS_TRADES_REQUIRED, BT_FILL_CONDITION_BUY_LIMIT, BT_FILL_CONDITION_SELL_LIMIT,BT_FILL_PRICE_MARKET_ORDER_PREMIUM):
+ self.symbol = symbol
+ self.BT_FILL_CONS_TRADES_REQUIRED = BT_FILL_CONS_TRADES_REQUIRED
+ self.BT_FILL_CONDITION_BUY_LIMIT=BT_FILL_CONDITION_BUY_LIMIT
+ self.BT_FILL_CONDITION_SELL_LIMIT=BT_FILL_CONDITION_SELL_LIMIT
+ self.BT_FILL_PRICE_MARKET_ORDER_PREMIUM=BT_FILL_PRICE_MARKET_ORDER_PREMIUM
+
+
""""
LATENCY DELAYS for LIVE eastcoast
.000 trigger - last_trade_time (.4246266)
diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py
index 9186c64..d98e0f3 100644
--- a/v2realbot/controller/services.py
+++ b/v2realbot/controller/services.py
@@ -6,20 +6,23 @@ from alpaca.data.requests import StockTradesRequest, StockBarsRequest
from alpaca.data.enums import DataFeed
from alpaca.data.timeframe import TimeFrame
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide
-from v2realbot.common.model import StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent, TestList, Intervals, ConfigItem
+from v2realbot.common.model import RunDay, StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent, TestList, Intervals, ConfigItem
from v2realbot.utils.utils import AttributeDict, zoneNY, dict_replace_value, Store, parse_toml_string, json_serial, is_open_hours, send_to_telegram
from v2realbot.utils.ilog import delete_logs
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType
from datetime import datetime
from threading import Thread, current_thread, Event, enumerate
-from v2realbot.config import STRATVARS_UNCHANGEABLES, ACCOUNT1_LIVE_API_KEY, ACCOUNT1_LIVE_SECRET_KEY, DATA_DIR,BT_FILL_CONS_TRADES_REQUIRED,BT_FILL_LOG_SURROUNDING_TRADES,BT_FILL_CONDITION_BUY_LIMIT,BT_FILL_CONDITION_SELL_LIMIT, GROUP_TRADES_WITH_TIMESTAMP_LESS_THAN
+from v2realbot.config import STRATVARS_UNCHANGEABLES, ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, ACCOUNT1_LIVE_API_KEY, ACCOUNT1_LIVE_SECRET_KEY, DATA_DIR,BT_FILL_CONS_TRADES_REQUIRED,BT_FILL_LOG_SURROUNDING_TRADES,BT_FILL_CONDITION_BUY_LIMIT,BT_FILL_CONDITION_SELL_LIMIT, GROUP_TRADES_WITH_TIMESTAMP_LESS_THAN
import importlib
+from alpaca.trading.requests import GetCalendarRequest
+from alpaca.trading.client import TradingClient
+#from alpaca.trading.models import Calendar
from queue import Queue
from tinydb import TinyDB, Query, where
from tinydb.operations import set
import json
from numpy import ndarray
-#from rich import print
+from rich import print
import pandas as pd
from traceback import format_exc
from datetime import timedelta, time
@@ -339,38 +342,93 @@ def get_testlist_byID(record_id: str):
return 0, TestList(id=row[0], name=row[1], dates=json.loads(row[2]))
+##TADY JSEM SKONCIL PROJIT - dodelat nastavni timezone
+#nejspis vse v RunDays by melo byt jiz lokalizovano na zoneNY
+#zaroven nejak vymyslet, aby bt_from/to uz bylo lokalizovano
+#ted jsem dal natvrdo v main rest lokalizaci
+#ale odtrasovat,ze vse funguje (nefunguje)
+
#volano pro batchove spousteni (BT,)
def run_batch_stratin(id: UUID, runReq: RunRequest):
- #pozor toto je test interval id (batch id se pak generuje pro kazdy davkovy run tohoto intervalu)
- if runReq.test_batch_id is None:
- return (-1, "batch_id required for batch run")
-
+ #pozor test_batch_id je test interval id (batch id se pak generuje pro kazdy davkovy run tohoto intervalu)
+ if runReq.test_batch_id is None and (runReq.bt_from is None or runReq.bt_from.date() == runReq.bt_to.date()):
+ return (-1, "test interval or different days required for batch run")
+
if runReq.mode != Mode.BT:
return (-1, "batch run only for backtest")
- print("request values:", runReq)
+ #print("request values:", runReq)
- print("getting intervals")
- testlist: TestList
+ #getting days to run into RunDays format
+ if runReq.test_batch_id is not None:
+ print("getting intervals days")
+ testlist: TestList
- res, testlist = get_testlist_byID(record_id=runReq.test_batch_id)
+ res, testlist = get_testlist_byID(record_id=runReq.test_batch_id)
- if res < 0:
- return (-1, f"not existing ID of testlists with {runReq.test_batch_id}")
+ if res < 0:
+ return (-1, f"not existing ID of testlists with {runReq.test_batch_id}")
+
+ print("test interval:", testlist)
+
+ cal_list = []
+ #interval dame do formatu list(RunDays)
+ #TODO do budoucna predelat Interval na RunDays a na zone aware datetime
+ for intrvl in testlist.dates:
+ start_time = zoneNY.localize(datetime.fromisoformat(intrvl.start))
+ end_time = zoneNY.localize(datetime.fromisoformat(intrvl.end))
+ cal_list.append(RunDay(start = start_time, end = end_time, note=intrvl.note, id=testlist.id))
+
+ print(f"Getting intervals - RESULT: {cal_list}")
+ #sem getting dates
+ else:
+ #getting dates from calendat
+ clientTrading = TradingClient(ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, raw_data=False)
+ if runReq.bt_to is None:
+ runReq.bt_to = datetime.now().astimezone(zoneNY)
+
+ calendar_request = GetCalendarRequest(start=runReq.bt_from,end=runReq.bt_to)
+ cal_dates = clientTrading.get_calendar(calendar_request)
+ #list(Calendar)
+ # Calendar
+ # date: date
+ # open: datetime
+ # close: datetime
+ cal_list = []
+ for day in cal_dates:
+ start_time = zoneNY.localize(day.open)
+ end_time = zoneNY.localize(day.close)
+
+ #u prvni polozky
+ if day == cal_dates[0]:
+ #pokud je cas od od vetsi nez open marketu prvniho dne, pouzijeme tento pozdejis cas
+ if runReq.bt_from > start_time:
+ start_time = runReq.bt_from
+
+ #u posledni polozky
+ if day == cal_dates[-1]:
+ #cas do, je pred openenem market, nedavame tento den
+ if runReq.bt_to < start_time:
+ continue
+ #pokud koncovy cas neni do konce marketu, pouzijeme tento drivejsi namisto konce posledniho dne
+ if runReq.bt_to < end_time:
+ end_time = runReq.bt_to
+ cal_list.append(RunDay(start = start_time, end = end_time))
+
+ print(f"Getting interval dates from - to - RESULT: {cal_list}")
#spousti se vlakno s paralelnim behem a vracime ok
- ridici_vlakno = Thread(target=batch_run_manager, args=(id, runReq, testlist), name=f"Batch run controll thread started.")
+ ridici_vlakno = Thread(target=batch_run_manager, args=(id, runReq, cal_list), name=f"Batch run control thread started.")
ridici_vlakno.start()
print(enumerate())
return 0, f"Batch run started"
-
#thread, ktery bude ridit paralelni spousteni
# bud ceka na dokonceni v runners nebo to bude ridit jinak a bude mit jednoho runnera?
# nejak vymyslet.
# logovani zatim jen do print
-def batch_run_manager(id: UUID, runReq: RunRequest, testlist: TestList):
+def batch_run_manager(id: UUID, runReq: RunRequest, rundays: list[RunDay]):
#zde muzu iterovat nad intervaly
#cekat az dobehne jeden interval a pak spustit druhy
#pripadne naplanovat beh - to uvidim
@@ -379,30 +437,21 @@ def batch_run_manager(id: UUID, runReq: RunRequest, testlist: TestList):
#mohl podporovat i BATCH RUNy.
batch_id = str(uuid4())[:8]
runReq.batch_id = batch_id
+ print("Entering BATCH RUN MANAGER")
print("generated batch_ID", batch_id)
- print("test batch", testlist)
-
- print("test date", testlist.dates)
- interval: Intervals
- cnt_max = len(testlist.dates)
+ cnt_max = len(rundays)
cnt = 0
#promenna pro sdileni mezi runy jednotlivych batchů (např. daily profit)
inter_batch_params = dict(batch_profit=0)
note_from_run_request = runReq.note
- for intrvl in testlist.dates:
+ for day in rundays:
cnt += 1
- interval = intrvl
- if interval.note is not None:
- print("mame zde note")
- print("Datum od", interval.start)
- print("Datum do", interval.end)
- print("starting")
-
- #předání atributů datetime.fromisoformat
- runReq.bt_from = datetime.fromisoformat(interval.start)
- runReq.bt_to = datetime.fromisoformat(interval.end)
- runReq.note = f"Batch {batch_id} #{cnt}/{cnt_max} {testlist.name} N:{interval.note} {note_from_run_request}"
+ print("Datum od", day.start)
+ print("Datum do", day.end)
+ runReq.bt_from = day.start
+ runReq.bt_to = day.end
+ runReq.note = f"Batch {batch_id} #{cnt}/{cnt_max} {day.name} N:{day.note} {note_from_run_request}"
#protoze jsme v ridicim vlaknu, poustime za sebou jednotlive stratiny v synchronnim modu
res, id_val = run_stratin(id=id, runReq=runReq, synchronous=True, inter_batch_params=inter_batch_params)
@@ -434,9 +483,9 @@ def run_stratin(id: UUID, runReq: RunRequest, synchronous: bool = False, inter_b
return (-1, "stratvars invalid")
res, adp = parse_toml_string(i.add_data_conf)
if res < 0:
- return (-1, "add data conf invalid")
- print("jsme uvnitr")
+ return (-1, "add data conf invalid")
id = uuid4()
+ print(f"RUN {id} INITIATED")
name = i.name
symbol = i.symbol
open_rush = i.open_rush
@@ -1114,6 +1163,7 @@ def get_alpaca_history_bars(symbol: str, datetime_object_from: datetime, datetim
#bars.data[symbol]
return 0, result
except Exception as e:
+ print(str(e) + format_exc())
return -2, str(e)
# change_archived_runner
diff --git a/v2realbot/main.py b/v2realbot/main.py
index 007a48d..05ccd33 100644
--- a/v2realbot/main.py
+++ b/v2realbot/main.py
@@ -24,7 +24,7 @@ from queue import Queue, Empty
from threading import Thread
import asyncio
from v2realbot.common.db import insert_queue, insert_conn, pool
-from v2realbot.utils.utils import json_serial, send_to_telegram
+from v2realbot.utils.utils import json_serial, send_to_telegram, zoneNY, zonePRG
from uuid import uuid4
from sqlite3 import OperationalError
from time import sleep
@@ -226,7 +226,14 @@ def _get_stratin(stratin_id) -> StrategyInstance:
@app.put("/stratins/{stratin_id}/run", dependencies=[Depends(api_key_auth)], status_code=status.HTTP_200_OK)
def _run_stratin(stratin_id: UUID, runReq: RunRequest):
#print(runReq)
- if runReq.test_batch_id is not None:
+ if runReq.bt_from is not None:
+ runReq.bt_from = zonePRG.localize(runReq.bt_from)
+
+ if runReq.bt_to is not None:
+ runReq.bt_to = zonePRG.localize(runReq.bt_to)
+ #pokud jedeme nad test intervaly anebo je požadováno více dní - pouštíme jako batch day by day
+ #do budoucna dát na FE jako flag
+ if runReq.test_batch_id is not None or (runReq.bt_from.date() != runReq.bt_to.date()):
res, id = cs.run_batch_stratin(id=stratin_id, runReq=runReq)
else:
res, id = cs.run_stratin(id=stratin_id, runReq=runReq)
diff --git a/v2realbot/static/index.html b/v2realbot/static/index.html
index 6c40716..9c4a3b1 100644
--- a/v2realbot/static/index.html
+++ b/v2realbot/static/index.html
@@ -82,6 +82,19 @@
+
+
diff --git a/v2realbot/static/js/archivechart.js b/v2realbot/static/js/archivechart.js
index e74aca3..cabae2a 100644
--- a/v2realbot/static/js/archivechart.js
+++ b/v2realbot/static/js/archivechart.js
@@ -298,6 +298,8 @@ function prepare_data(archRunner, timeframe_amount, timeframe_unit, archivedRunn
//$("#statusStratvars").text(JSON.stringify(data.stratvars,null,2))
},
error: function(xhr, status, error) {
+ oneMinuteBars = null
+ chart_archived_run(archRunner, archivedRunnerDetail, oneMinuteBars);
var err = eval("(" + xhr.responseText + ")");
window.alert(JSON.stringify(xhr));
console.log(JSON.stringify(xhr));
@@ -357,6 +359,7 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
candlestickSeries = null
+ //v pripade, ze neprojde get bars, nastavit na intervals[0]
switch_to_interval(intervals[1])
chart.timeScale().fitContent();
@@ -963,11 +966,11 @@ function display_log(iterLogList, timestamp) {
highlighted = (parseInt(logLine.time) == parseInt(timestamp)) ? "highlighted" : ""
logcnt++;
- row = '
'+logLine.time + " " + logLine.event + ' - '+ (logLine.message == undefined ? "" : logLine.message) +'
'
+ row = ''+logLine.time + " " + logLine.event + ' - '+ (logLine.message == undefined ? "" : logLine.message) +'
'
str_row = JSON.stringify(logLine.details, null, 2)
//row_detail = ''
- row_detail = ''
+ row_detail = ''
var lines = document.getElementById('lines')
var line = document.createElement('div')
diff --git a/v2realbot/static/js/libs/atom-dark.css b/v2realbot/static/js/libs/atom-dark.css
new file mode 100644
index 0000000..de8ef1a
--- /dev/null
+++ b/v2realbot/static/js/libs/atom-dark.css
@@ -0,0 +1,157 @@
+[class*=shj-lang-] {
+ white-space: pre;
+ /* margin: 10px 0; */
+ /* border-radius: 10px; */
+ /* padding: 30px 20px; */
+ background: white;
+ color: #112;
+ box-shadow: 0 0 5px #0001;
+ text-shadow: none;
+ font: 11px Consolas,Courier New,Monaco,Andale Mono,Ubuntu Mono,monospace;
+ line-height: 15px;
+ box-sizing: border-box;
+ /* max-width: min(100%,100vw); */
+ word-wrap: normal;
+}
+
+.shj-inline {
+ margin: 0;
+ padding: 2px 5px;
+ display: inline-block;
+ border-radius: 5px
+}
+
+[class*=shj-lang-]::selection,[class*=shj-lang-] ::selection {
+ background: #bdf5
+}
+
+[class*=shj-lang-]>div {
+ display: flex;
+ overflow: auto
+}
+
+[class*=shj-lang-]>div :last-child {
+ flex: 1;
+ outline: none
+}
+
+.shj-numbers {
+ padding-left: 5px;
+ counter-reset: line
+}
+
+.shj-numbers div {
+ padding-right: 5px
+}
+
+.shj-numbers div:before {
+ color: #999;
+ display: block;
+ content: counter(line);
+ opacity: .5;
+ text-align: right;
+ margin-right: 5px;
+ counter-increment: line
+}
+
+.shj-syn-cmnt {
+ font-style: italic
+}
+
+.shj-syn-err,.shj-syn-kwd {
+ color: #e16
+}
+
+.shj-syn-num,.shj-syn-class {
+ color: #f60
+}
+
+.shj-numbers,.shj-syn-cmnt {
+ color: #999
+}
+
+.shj-syn-insert,.shj-syn-str {
+ color: #7d8
+}
+
+.shj-syn-bool {
+ color: #3bf
+}
+
+.shj-syn-type,.shj-syn-oper {
+ color: #5af
+}
+
+.shj-syn-section,.shj-syn-func {
+ color: #84f
+}
+
+.shj-syn-deleted,.shj-syn-var {
+ color: #f44
+}
+
+.shj-oneline {
+ padding: 12px 10px
+}
+
+.shj-lang-http.shj-oneline .shj-syn-kwd {
+ background: #25f;
+ color: #fff;
+ padding: 5px 7px;
+ border-radius: 5px
+}
+
+.shj-multiline.shj-mode-header {
+ padding: 20px
+}
+
+.shj-multiline.shj-mode-header:before {
+ content: attr(data-lang);
+ color: #58f;
+ display: block;
+ padding: 10px 20px;
+ background: #58f3;
+ border-radius: 5px;
+ margin-bottom: 20px
+}
+
+[class*=shj-lang-] {
+ color: #abb2bf;
+ background: #161b22
+}
+
+[class*=shj-lang-]:before {
+ color: #6f9aff
+}
+
+.shj-syn-deleted,.shj-syn-err,.shj-syn-var {
+ color: #e06c75
+}
+
+.shj-syn-section,.shj-syn-oper,.shj-syn-kwd {
+ color: #c678dd
+}
+
+.shj-syn-class {
+ color: #e5c07b
+}
+
+.shj-numbers,.shj-syn-cmnt {
+ color: #76839a
+}
+
+.shj-syn-insert {
+ color: #98c379
+}
+
+.shj-syn-type {
+ color: #56b6c2
+}
+
+.shj-syn-num,.shj-syn-bool {
+ color: #d19a66
+}
+
+.shj-syn-str,.shj-syn-func {
+ color: #61afef
+}
diff --git a/v2realbot/static/main.css b/v2realbot/static/main.css
index 5d6eccf..f694729 100644
--- a/v2realbot/static/main.css
+++ b/v2realbot/static/main.css
@@ -278,7 +278,7 @@ html {
height: 568px;
flex-direction: column-reverse;
margin-left: 28px;
- width: 100%;
+ width: 130%;
}
#lowercontainer {
diff --git a/v2realbot/strategyblocks/activetrade/sl/trailsl.py b/v2realbot/strategyblocks/activetrade/sl/trailsl.py
index aa0a5ed..ea510e3 100644
--- a/v2realbot/strategyblocks/activetrade/sl/trailsl.py
+++ b/v2realbot/strategyblocks/activetrade/sl/trailsl.py
@@ -63,27 +63,30 @@ def trail_SL_management(state: StrategyState, data):
def_SL = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(options, directive_name, 0.01))
directive_name = "SL_trailing_offset_"+str(smer)
offset = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(options, directive_name, 0.01))
+ directive_name = "SL_trailing_step_"+str(smer)
+ step = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(options, directive_name, offset))
#pokud je pozadovan trail jen do breakeven a uz prekroceno
if (direction == TradeDirection.LONG and stop_breakeven and state.vars.activeTrade.stoploss_value >= float(state.avgp)) or (direction == TradeDirection.SHORT and stop_breakeven and state.vars.activeTrade.stoploss_value <= float(state.avgp)):
state.ilog(lvl=1,e=f"SL trail STOP at breakeven {str(smer)} SL:{state.vars.activeTrade.stoploss_value} UNCHANGED", stop_breakeven=stop_breakeven)
return
- #IDEA: Nyni posouvame SL o offset, mozna ji posunout jen o direktivu step ?
+ #Aktivace SL pokud vystoupa na "offset", a nasledne posunuti o "step"
offset_normalized = normalize_tick(state, data, offset) #to ticks and from options
+ step_normalized = normalize_tick(state, data, step)
def_SL_normalized = normalize_tick(state, data, def_SL)
if direction == TradeDirection.LONG:
move_SL_threshold = state.vars.activeTrade.stoploss_value + offset_normalized + def_SL_normalized
- state.ilog(lvl=1,e=f"SL TRAIL EVAL {smer} SL:{round(state.vars.activeTrade.stoploss_value,3)} TRAILGOAL:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
+ state.ilog(lvl=1,e=f"SL TRAIL EVAL {smer} SL:{round(state.vars.activeTrade.stoploss_value,3)} TRAILGOAL:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, step_normalized=step_normalized, def_SL_normalized=def_SL_normalized)
if (move_SL_threshold) < data['close']:
- state.vars.activeTrade.stoploss_value += offset_normalized
+ state.vars.activeTrade.stoploss_value += step_normalized
insert_SL_history(state)
- state.ilog(lvl=1,e=f"SL TRAIL TH {smer} reached {move_SL_threshold} SL moved to {state.vars.activeTrade.stoploss_value}", offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
+ state.ilog(lvl=1,e=f"SL TRAIL TH {smer} reached {move_SL_threshold} SL moved to {state.vars.activeTrade.stoploss_value}", offset_normalized=offset_normalized, step_normalized=step_normalized, def_SL_normalized=def_SL_normalized)
elif direction == TradeDirection.SHORT:
move_SL_threshold = state.vars.activeTrade.stoploss_value - offset_normalized - def_SL_normalized
- state.ilog(lvl=0,e=f"SL TRAIL EVAL {smer} SL:{round(state.vars.activeTrade.stoploss_value,3)} TRAILGOAL:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
+ state.ilog(lvl=0,e=f"SL TRAIL EVAL {smer} SL:{round(state.vars.activeTrade.stoploss_value,3)} TRAILGOAL:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, step_normalized=step_normalized, def_SL_normalized=def_SL_normalized)
if (move_SL_threshold) > data['close']:
- state.vars.activeTrade.stoploss_value -= offset_normalized
+ state.vars.activeTrade.stoploss_value -= step_normalized
insert_SL_history(state)
- state.ilog(lvl=1,e=f"SL TRAIL GOAL {smer} reached {move_SL_threshold} SL moved to {state.vars.activeTrade.stoploss_value}", offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
+ state.ilog(lvl=1,e=f"SL TRAIL GOAL {smer} reached {move_SL_threshold} SL moved to {state.vars.activeTrade.stoploss_value}", offset_normalized=offset_normalized, step_normalized=step_normalized, def_SL_normalized=def_SL_normalized)
diff --git a/v2realbot/strategyblocks/indicators/custom/__init__.py b/v2realbot/strategyblocks/indicators/custom/__init__.py
index b6e690f..b71e431 100644
--- a/v2realbot/strategyblocks/indicators/custom/__init__.py
+++ b/v2realbot/strategyblocks/indicators/custom/__init__.py
@@ -1 +1,10 @@
-from . import *
+import os
+# import importlib
+# from v2realbot.strategyblocks.indicators.custom.opengap import opengap
+
+for filename in os.listdir("v2realbot/strategyblocks/indicators/custom"):
+ if filename.endswith(".py") and filename != "__init__.py":
+ # __import__(filename[:-3])
+ __import__(f"v2realbot.strategyblocks.indicators.custom.{filename[:-3]}")
+ #importlib.import_module()
+
diff --git a/v2realbot/strategyblocks/indicators/custom/basestats.py b/v2realbot/strategyblocks/indicators/custom/basestats.py
index 142ec4c..50d8cf2 100644
--- a/v2realbot/strategyblocks/indicators/custom/basestats.py
+++ b/v2realbot/strategyblocks/indicators/custom/basestats.py
@@ -35,6 +35,32 @@ def basestats(state, params):
val = np.amax(source_array)
elif func == "mean":
val = np.mean(source_array)
+ elif func == "var":
+ data = np.array(source_array)
+ mean_value = np.mean(data)
+ # Calculate the variance of the data
+ val = np.mean((data - mean_value) ** 2)
+ elif func == "angle":
+ delka_pole = len(source_array)
+ if delka_pole < 2:
+ return 0,0
+
+ x = np.arange(delka_pole)
+ y = np.array(source_array)
+
+ # Fit a linear polynomial to the data
+ coeffs = np.polyfit(x, y, 1)
+
+ # Calculate the angle in radians angle_rad
+ val = np.arctan(coeffs[0]) * 1000
+
+ # Convert the angle to degrees angle_deg
+ #angle_deg = np.degrees(angle_rad)
+
+ # Normalize the degrees between -1 and 1
+ #val = 2 * (angle_deg / 180) - 1
+ elif func =="stdev":
+ val = np.std(source_array)
else:
return -2, "wrong function"
diff --git a/v2realbot/strategyblocks/indicators/custom/ema.py b/v2realbot/strategyblocks/indicators/custom/ema.py
new file mode 100644
index 0000000..d0a8693
--- /dev/null
+++ b/v2realbot/strategyblocks/indicators/custom/ema.py
@@ -0,0 +1,26 @@
+from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
+from v2realbot.strategy.base import StrategyState
+from v2realbot.indicators.indicators import ema as ext_ema
+from v2realbot.strategyblocks.indicators.helpers import get_source_series
+from rich import print as printanyway
+from traceback import format_exc
+from v2realbot.ml.ml import ModelML
+import numpy as np
+from collections import defaultdict
+from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
+#strength, absolute change of parameter between current value and lookback value (n-past)
+#used for example to measure unusual peaks
+def ema(state, params):
+ funcName = "ema"
+ source = safe_get(params, "source", None)
+ lookback = safe_get(params, "lookback",14)
+
+ #lookback muze byt odkaz na indikator, pak berem jeho hodnotu
+ lookback = int(value_or_indicator(state, lookback))
+
+ source_series = get_source_series(state, source)[-lookback:]
+ ema_value = ext_ema(source_series, lookback)
+ val = round(ema_value[-1],4)
+
+ state.ilog(lvl=1,e=f"INSIDE {funcName} {val} {source=} {lookback=}", **params)
+ return 0, val
\ No newline at end of file
diff --git a/v2realbot/strategyblocks/indicators/custom/mathop.py b/v2realbot/strategyblocks/indicators/custom/mathop.py
index f342789..1828aae 100644
--- a/v2realbot/strategyblocks/indicators/custom/mathop.py
+++ b/v2realbot/strategyblocks/indicators/custom/mathop.py
@@ -15,13 +15,16 @@ def mathop(state, params):
if source1 is None or source2 is None or operator is None:
return -2, "required source1 source2 operator"
+ druhy = float(value_or_indicator(state, source2))
if operator == "+":
- val = round(float(source1_series[-1] + value_or_indicator(state, source2)),4)
+ val = round(float(source1_series[-1] + druhy),4)
elif operator == "-":
- val = round(float(source1_series[-1] - value_or_indicator(state, source2)),4)
+ val = round(float(source1_series[-1] - druhy),4)
+ elif operator == "*":
+ val = round(float(source1_series[-1] * druhy),4)
else:
return -2, "unknow operator"
- #state.ilog(lvl=0,e=f"INSIDE {funcName} {source1=} {source2=} {val}", **params)
+ state.ilog(lvl=1,e=f"INSIDE {funcName} {source1=} {source2=} {val} {druhy=}", **params)
return 0, val
diff --git a/v2realbot/strategyblocks/indicators/custom/sameprice.py b/v2realbot/strategyblocks/indicators/custom/sameprice.py
new file mode 100644
index 0000000..696060d
--- /dev/null
+++ b/v2realbot/strategyblocks/indicators/custom/sameprice.py
@@ -0,0 +1,52 @@
+from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
+from v2realbot.strategy.base import StrategyState
+from v2realbot.indicators.indicators import ema, natr, roc
+from v2realbot.strategyblocks.indicators.helpers import get_source_series
+from rich import print as printanyway
+from traceback import format_exc
+from v2realbot.ml.ml import ModelML
+import numpy as np
+from collections import defaultdict
+import bisect
+
+#strength, absolute change of parameter between current value and lookback value (n-past)
+#used for example to measure unusual peaks
+def sameprice(state, params):
+ funcName = "sameprice"
+ typ = safe_get(params, "type", None)
+
+ def find_first_bigger_than_lastitem_backwards(list1):
+ last_item = list1[-1]
+ for i in range(len(list1) - 2, -1, -1):
+ if list1[i] > last_item:
+ return i
+ return -1
+
+ def find_first_smaller_than_lastitem_backwards(list1):
+ last_item = list1[-1]
+ for i in range(len(list1) - 2, -1, -1):
+ if list1[i] < last_item:
+ return i
+ return -1
+
+ if typ == "up":
+ pozice_prvniho_vetsiho = find_first_bigger_than_lastitem_backwards(state.bars["vwap"])
+ elif typ == "down":
+ pozice_prvniho_vetsiho = find_first_smaller_than_lastitem_backwards(state.bars["vwap"])
+ else:
+ return -2, "unknow type"
+
+ celkova_delka = len(state.bars["vwap"])
+
+ #jde o daily high
+ if pozice_prvniho_vetsiho == -1:
+ state.ilog(lvl=1,e=f"INSIDE {funcName} {typ} {pozice_prvniho_vetsiho=} vracime 1")
+ return 0, celkova_delka
+
+ delka_k_predchozmu = celkova_delka - pozice_prvniho_vetsiho
+ normalizovano = delka_k_predchozmu/celkova_delka
+
+ state.ilog(lvl=1,e=f"INSIDE {funcName} {typ} {pozice_prvniho_vetsiho=} {celkova_delka=} {delka_k_predchozmu=} {normalizovano=}", pozice_prvniho_vetsiho=pozice_prvniho_vetsiho, celkova_delka=celkova_delka, delka_k_predchozmu=delka_k_predchozmu, **params)
+
+ return 0, delka_k_predchozmu
+
diff --git a/v2realbot/strategyblocks/indicators/custom/custom_hub.py b/v2realbot/strategyblocks/indicators/custom_hub.py
similarity index 92%
rename from v2realbot/strategyblocks/indicators/custom/custom_hub.py
rename to v2realbot/strategyblocks/indicators/custom_hub.py
index 092c46a..db6a1af 100644
--- a/v2realbot/strategyblocks/indicators/custom/custom_hub.py
+++ b/v2realbot/strategyblocks/indicators/custom_hub.py
@@ -8,15 +8,16 @@ import importlib
#TODO TENTO IMPORT VYMYSLET, abych naloadoval package custom a nemusel nic pridat (vymyslet dynamicke volani z cele package ci)
#from v2realbot.strategyblocks.indicators.custom._upscaled_rsi_wip import upscaledrsi
-from v2realbot.strategyblocks.indicators.custom.barparams import barparams
-from v2realbot.strategyblocks.indicators.custom.basestats import basestats
-from v2realbot.strategyblocks.indicators.custom.delta import delta
-from v2realbot.strategyblocks.indicators.custom.divergence import divergence
-from v2realbot.strategyblocks.indicators.custom.model import model
-from v2realbot.strategyblocks.indicators.custom.opengap import opengap
-from v2realbot.strategyblocks.indicators.custom.slope import slope
-from v2realbot.strategyblocks.indicators.custom.conditional import conditional
-from v2realbot.strategyblocks.indicators.custom.mathop import mathop
+import v2realbot.strategyblocks.indicators.custom as ci
+# from v2realbot.strategyblocks.indicators.custom.barparams import barparams
+# from v2realbot.strategyblocks.indicators.custom.basestats import basestats
+# from v2realbot.strategyblocks.indicators.custom.delta import delta
+# from v2realbot.strategyblocks.indicators.custom.divergence import divergence
+# from v2realbot.strategyblocks.indicators.custom.model import model
+# from v2realbot.strategyblocks.indicators.custom.opengap import opengap
+# from v2realbot.strategyblocks.indicators.custom.slope import slope
+# from v2realbot.strategyblocks.indicators.custom.conditional import conditional
+# from v2realbot.strategyblocks.indicators.custom.mathop import mathop
# import v2realbot.strategyblocks.indicators.custom as ci
@@ -143,7 +144,7 @@ def populate_dynamic_custom_indicator(data, state: StrategyState, name):
#pozor jako defaultní hodnotu dává engine 0 - je to ok?
try:
- #subtype = "ci."+subtype
+ subtype = "ci."+subtype+"."+subtype
custom_function = eval(subtype)
res_code, new_val = custom_function(state, custom_params)
if res_code == 0:
diff --git a/v2realbot/strategyblocks/indicators/helpers.py b/v2realbot/strategyblocks/indicators/helpers.py
index 04c1c76..27aec3b 100644
--- a/v2realbot/strategyblocks/indicators/helpers.py
+++ b/v2realbot/strategyblocks/indicators/helpers.py
@@ -1,4 +1,4 @@
-from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
+from v2realbot.utils.utils import isrising, isfalling,isfallingc, isrisingc, zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
from v2realbot.strategy.base import StrategyState
from traceback import format_exc
@@ -9,13 +9,16 @@ from traceback import format_exc
def value_or_indicator(state,value):
#preklad direktivy podle typu, pokud je int anebo float - je to primo hodnota
#pokud je str, jde o indikator a dotahujeme posledni hodnotu z nej
- if isinstance(value, (int, float)):
+ if isinstance(value, (float, int)):
return value
elif isinstance(value, str):
try:
#pokud existuje v indikatoru MA bereme MA jinak indikator, pokud neexistuje bereme bar
ret = get_source_or_MA(state, indicator=value)[-1]
- state.ilog(lvl=0,e=f"Pro porovnani bereme posledni hodnotu {ret} z indikatoru {value}")
+ lvl = 0
+ if ret == 0:
+ lvl = 1
+ state.ilog(lvl=lvl,e=f"Pro porovnani bereme posledni hodnotu {ret} z indikatoru {value}")
except Exception as e :
ret = 0
state.ilog(lvl=1,e=f"Neexistuje indikator s nazvem {value} vracime 0" + str(e) + format_exc())
@@ -38,6 +41,8 @@ def evaluate_directive_conditions(state, work_dict, cond_type):
"above": lambda ind, val: get_source_or_MA(state, ind)[-1] > value_or_indicator(state,val),
"equals": lambda ind, val: get_source_or_MA(state, ind)[-1] == value_or_indicator(state,val),
"below": lambda ind, val: get_source_or_MA(state, ind)[-1] < value_or_indicator(state,val),
+ "fallingc": lambda ind, val: isfallingc(get_source_or_MA(state, ind), val),
+ "risingc": lambda ind, val: isrisingc(get_source_or_MA(state, ind), val),
"falling": lambda ind, val: isfalling(get_source_or_MA(state, ind), val),
"rising": lambda ind, val: isrising(get_source_or_MA(state, ind), val),
"crossed_down": lambda ind, val: buy_if_crossed_down(state, ind, value_or_indicator(state,val)),
diff --git a/v2realbot/strategyblocks/indicators/indicators_hub.py b/v2realbot/strategyblocks/indicators/indicators_hub.py
index b62b158..cd899d7 100644
--- a/v2realbot/strategyblocks/indicators/indicators_hub.py
+++ b/v2realbot/strategyblocks/indicators/indicators_hub.py
@@ -1,7 +1,7 @@
from v2realbot.strategy.base import StrategyState
from v2realbot.strategyblocks.indicators.cbar_price import populate_cbar_tick_price_indicator
-from v2realbot.strategyblocks.indicators.custom.custom_hub import populate_dynamic_custom_indicator
+from v2realbot.strategyblocks.indicators.custom_hub import populate_dynamic_custom_indicator
from v2realbot.strategyblocks.indicators.slope import populate_dynamic_slope_indicator
from v2realbot.strategyblocks.indicators.slopeLP import populate_dynamic_slopeLP_indicator
from v2realbot.strategyblocks.indicators.ema import populate_dynamic_ema_indicator
diff --git a/v2realbot/strategyblocks/newtrade/conditions.py b/v2realbot/strategyblocks/newtrade/conditions.py
index bfe78c0..b60c82f 100644
--- a/v2realbot/strategyblocks/newtrade/conditions.py
+++ b/v2realbot/strategyblocks/newtrade/conditions.py
@@ -33,18 +33,18 @@ def go_conditions_met(state, data, signalname: str, direction: TradeDirection):
#dont_buy_above = value nebo hazev indikatoru
#TESTUJEME SPECIFICKY DONT_GO -
- #u techto ma smysl pouze OR
+ #jak OR tak i AND
cond_dict = state.vars.conditions[KW.dont_go][signalname][smer]
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
- state.ilog(lvl=1,e=f"SPECIFIC PRECOND {smer} {result}", **conditions_met, cond_dict=cond_dict)
+ state.ilog(lvl=1,e=f"SPECIFIC PRECOND =OR= {smer} {result}", **conditions_met, cond_dict=cond_dict)
+ if result:
+ return False
+
+ #OR neprosly testujeme AND
+ result, conditions_met = evaluate_directive_conditions(state, cond_dict, "AND")
+ state.ilog(lvl=1,e=f"SPECIFIC PRECOND =AND={smer} {result}", **conditions_met, cond_dict=cond_dict)
if result:
return False
-
- # #OR neprosly testujeme AND
- # result, conditions_met = evaluate_directive_conditions(cond_dict, "AND")
- # state.ilog(lvl=0,e=f"EXIT CONDITIONS of activeTrade {smer} =AND= {result}", **conditions_met, cond_dict=cond_dict)
- # if result:
- # return True
#tyto timto nahrazeny - dat do konfigurace (dont_short_when, dont_long_when)
#dont_buy_when['rsi_too_high'] = state.indicators.RSI14[-1] > safe_get(state.vars, "rsi_dont_buy_above",50)
@@ -110,7 +110,7 @@ def common_go_preconditions_check(state, data, signalname: str, options: dict):
if state.vars.last_exit_index is not None:
index_to_compare = int(state.vars.last_exit_index)+int(next_signal_offset)
if index_to_compare > int(data["index"]):
- state.ilog(lvl=1,e=f"NEXT SIGNAL OFFSET from EXIT {next_signal_offset} waiting - TOO SOON", currindex=data["index"], index_to_compare=index_to_compare, last_exit_index=state.vars.last_exit_index)
+ state.ilog(lvl=1,e=f"NEXT SIGNAL OFFSET from EXIT {next_signal_offset} waiting - TOO SOON {signalname}", currindex=data["index"], index_to_compare=index_to_compare, last_exit_index=state.vars.last_exit_index)
return False
# if is_open_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), open_rush) or is_close_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), close_rush):
diff --git a/v2realbot/strategyblocks/newtrade/prescribedtrades.py b/v2realbot/strategyblocks/newtrade/prescribedtrades.py
index 4730576..d4637cd 100644
--- a/v2realbot/strategyblocks/newtrade/prescribedtrades.py
+++ b/v2realbot/strategyblocks/newtrade/prescribedtrades.py
@@ -45,7 +45,7 @@ def execute_prescribed_trades(state: StrategyState, data):
res = state.buy(size=size)
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation LONG {res}")
- #nastaveni SL az do notifikace, kdy je známá
+ #TODO nastaveni SL az do notifikace, kdy je známá
#pokud neni nastaveno SL v prescribe, tak nastavuji default dle stratvars
if state.vars.activeTrade.stoploss_value is None:
sl_defvalue = get_default_sl_value(state, direction=state.vars.activeTrade.direction)
diff --git a/v2realbot/strategyblocks/newtrade/signals.py b/v2realbot/strategyblocks/newtrade/signals.py
index 217e3dc..b9b1040 100644
--- a/v2realbot/strategyblocks/newtrade/signals.py
+++ b/v2realbot/strategyblocks/newtrade/signals.py
@@ -38,7 +38,7 @@ def signal_search(state: StrategyState, data):
# to vse za predpokladu, ze neni aktivni trade
def execute_signal_generator(state, data, name):
- state.ilog(lvl=0,e=f"SIGNAL SEARCH for {name}", cond_go=state.vars.conditions[KW.go][name], cond_dontgo=state.vars.conditions[KW.dont_go][name], cond_activate=state.vars.conditions[KW.activate][name] )
+ state.ilog(lvl=1,e=f"SIGNAL SEARCH for {name}", cond_go=state.vars.conditions[KW.go][name], cond_dontgo=state.vars.conditions[KW.dont_go][name], cond_activate=state.vars.conditions[KW.activate][name] )
options = safe_get(state.vars.signals, name, None)
if options is None:
@@ -60,7 +60,7 @@ def execute_signal_generator(state, data, name):
custom_function = eval(signal_plugin)
custom_function()
except NameError:
- state.ilog(lvl=1,e="Custom plugin {signal_plugin} not found")
+ state.ilog(lvl=1,e=f"Custom plugin {signal_plugin} not found")
else:
short_enabled = safe_get(options, "short_enabled",safe_get(state.vars, "short_enabled",True))
long_enabled = safe_get(options, "long_enabled",safe_get(state.vars, "long_enabled",True))
diff --git a/v2realbot/utils/utils.py b/v2realbot/utils/utils.py
index 51d195d..875e272 100644
--- a/v2realbot/utils/utils.py
+++ b/v2realbot/utils/utils.py
@@ -408,6 +408,8 @@ qu = Queue()
#zoneNY = tz.gettz('America/New_York')
zoneNY = pytz.timezone('US/Eastern')
+zonePRG = pytz.timezone('Europe/Amsterdam')
+
def print(*args, **kwargs):
if QUIET_MODE:
pass
@@ -567,8 +569,8 @@ def is_open_hours(dt, business_hours: dict = None):
and dt.date() not in holidays \
and business_hours["from"] <= dt.time() < business_hours["to"]
-#vraci zda dane pole je klesajici (bud cele a nebo jen pocet poslednich)
-def isfalling_old(pole: list, pocet: int = None):
+#vraci zda dane pole je klesajici (bud cele a nebo jen pocet poslednich) - no same values
+def isfallingc(pole: list, pocet: int = None):
if pocet is None: pocet = len(pole)
if len(pole) j for i, j in zip(new_pole, new_pole[1:]))
return res
-#vraci zda dane pole je roustouci (bud cele a nebo jen pocet poslednich)
-def isrising_old(pole: list, pocet: int = None):
+#vraci zda dane pole je roustouci (bud cele a nebo jen pocet poslednich) - no same values
+def isrisingc(pole: list, pocet: int = None):
if pocet is None: pocet = len(pole)
if len(pole)