Compare commits
5 Commits
feature/to
...
bug/attach
| Author | SHA1 | Date | |
|---|---|---|---|
| 50ad60fa12 | |||
| adc7c3c1b6 | |||
| a6343abe88 | |||
| 075984fcff | |||
| 5fce627fe3 |
@ -524,7 +524,7 @@ class Backtester:
|
|||||||
if actual_minus_reserved <= 0:
|
if actual_minus_reserved <= 0:
|
||||||
cena = price if price else self.get_last_price(time, self.symbol)
|
cena = price if price else self.get_last_price(time, self.symbol)
|
||||||
if (self.cash - reserved_price - float(int(size)*float(cena))) < 0:
|
if (self.cash - reserved_price - float(int(size)*float(cena))) < 0:
|
||||||
printanyway("not enough cash for shorting. cash",self.cash,"reserved",reserved,"available",self.cash-reserved,"needed",float(int(size)*float(cena)))
|
printanyway("ERROR: not enough cash for shorting. cash",self.cash,"reserved",reserved,"available",self.cash-reserved,"needed",float(int(size)*float(cena)))
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
#check for available cash
|
#check for available cash
|
||||||
@ -550,7 +550,7 @@ class Backtester:
|
|||||||
if actual_plus_reserved_qty >= 0:
|
if actual_plus_reserved_qty >= 0:
|
||||||
cena = price if price else self.get_last_price(time, self.symbol)
|
cena = price if price else self.get_last_price(time, self.symbol)
|
||||||
if (self.cash - reserved_price - float(int(size)*float(cena))) < 0:
|
if (self.cash - reserved_price - float(int(size)*float(cena))) < 0:
|
||||||
printanyway("not enough cash to buy long. cash",self.cash,"reserved_qty",reserved_qty,"reserved_price",reserved_price, "available",self.cash-reserved_price,"needed",float(int(size)*float(cena)))
|
printanyway("ERROR: not enough cash to buy long. cash",self.cash,"reserved_qty",reserved_qty,"reserved_price",reserved_price, "available",self.cash-reserved_price,"needed",float(int(size)*float(cena)))
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
id = str(uuid4())
|
id = str(uuid4())
|
||||||
|
|||||||
@ -3,7 +3,7 @@ from uuid import UUID, uuid4
|
|||||||
import pickle
|
import pickle
|
||||||
from alpaca.data.historical import StockHistoricalDataClient
|
from alpaca.data.historical import StockHistoricalDataClient
|
||||||
from alpaca.data.requests import StockTradesRequest, StockBarsRequest
|
from alpaca.data.requests import StockTradesRequest, StockBarsRequest
|
||||||
from alpaca.data.enums import DataFeed
|
from alpaca.data.enums import DataFeed
|
||||||
from alpaca.data.timeframe import TimeFrame
|
from alpaca.data.timeframe import TimeFrame
|
||||||
from v2realbot.strategy.base import StrategyState
|
from v2realbot.strategy.base import StrategyState
|
||||||
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide
|
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide
|
||||||
@ -103,10 +103,10 @@ def create_stratin(si: StrategyInstance):
|
|||||||
#validate toml
|
#validate toml
|
||||||
res, stp = parse_toml_string(si.stratvars_conf)
|
res, stp = parse_toml_string(si.stratvars_conf)
|
||||||
if res < 0:
|
if res < 0:
|
||||||
return (-1,"stratvars invalid")
|
return (-1,f"stratvars invalid: {stp}")
|
||||||
res, adp = parse_toml_string(si.add_data_conf)
|
res, adp = parse_toml_string(si.add_data_conf)
|
||||||
if res < 0:
|
if res < 0:
|
||||||
return (-1, "None")
|
return (-1, f"add data conf invalid {adp}")
|
||||||
si.id = uuid4()
|
si.id = uuid4()
|
||||||
#print(si)
|
#print(si)
|
||||||
db.stratins.append(si)
|
db.stratins.append(si)
|
||||||
@ -120,10 +120,10 @@ def modify_stratin(si: StrategyInstance, id: UUID):
|
|||||||
return (-1, "strat is running, use modify_stratin_running")
|
return (-1, "strat is running, use modify_stratin_running")
|
||||||
res, stp = parse_toml_string(si.stratvars_conf)
|
res, stp = parse_toml_string(si.stratvars_conf)
|
||||||
if res < 0:
|
if res < 0:
|
||||||
return (-1, "stratvars invalid")
|
return (-1, f"stratvars invalid {stp}")
|
||||||
res, adp = parse_toml_string(si.add_data_conf)
|
res, adp = parse_toml_string(si.add_data_conf)
|
||||||
if res < 0:
|
if res < 0:
|
||||||
return (-1, "add data conf invalid")
|
return (-1, f"add data conf invalid {adp}")
|
||||||
for i in db.stratins:
|
for i in db.stratins:
|
||||||
if str(i.id) == str(id):
|
if str(i.id) == str(id):
|
||||||
#print("removing",i)
|
#print("removing",i)
|
||||||
@ -181,14 +181,14 @@ def modify_stratin_running(si: StrategyInstance, id: UUID):
|
|||||||
#validate toml
|
#validate toml
|
||||||
res,stp = parse_toml_string(si.stratvars_conf)
|
res,stp = parse_toml_string(si.stratvars_conf)
|
||||||
if res < 0:
|
if res < 0:
|
||||||
return (-1, "new stratvars format invalid")
|
return (-1, f"new stratvars format invalid {stp}")
|
||||||
for i in db.stratins:
|
for i in db.stratins:
|
||||||
if str(i.id) == str(id):
|
if str(i.id) == str(id):
|
||||||
if not is_stratin_running(id=str(id)):
|
if not is_stratin_running(id=str(id)):
|
||||||
return (-1, "not running")
|
return (-1, "not running")
|
||||||
res,stp_old = parse_toml_string(i.stratvars_conf)
|
res,stp_old = parse_toml_string(i.stratvars_conf)
|
||||||
if res < 0:
|
if res < 0:
|
||||||
return (-1, "current stratin stratvars invalid")
|
return (-1, f"current stratin stratvars invalid {stp_old}")
|
||||||
#TODO reload running strat
|
#TODO reload running strat
|
||||||
#print(stp)
|
#print(stp)
|
||||||
#print("starting injection", stp)
|
#print("starting injection", stp)
|
||||||
@ -447,7 +447,7 @@ def run_batch_stratin(id: UUID, runReq: RunRequest):
|
|||||||
cal_list.append(RunDay(start = start_time, end = end_time, note = note, id = id))
|
cal_list.append(RunDay(start = start_time, end = end_time, note = note, id = id))
|
||||||
|
|
||||||
print(f"Getting interval dates from - to - RESULT ({len(cal_list)}):")
|
print(f"Getting interval dates from - to - RESULT ({len(cal_list)}):")
|
||||||
print(cal_list)
|
#print(cal_list)
|
||||||
return cal_list
|
return cal_list
|
||||||
|
|
||||||
#getting days to run into RunDays format
|
#getting days to run into RunDays format
|
||||||
@ -619,10 +619,10 @@ def run_stratin(id: UUID, runReq: RunRequest, synchronous: bool = False, inter_b
|
|||||||
#validate toml
|
#validate toml
|
||||||
res, stp = parse_toml_string(i.stratvars_conf)
|
res, stp = parse_toml_string(i.stratvars_conf)
|
||||||
if res < 0:
|
if res < 0:
|
||||||
return (-1, "stratvars invalid")
|
return (-1, f"stratvars invalid {stp}")
|
||||||
res, adp = parse_toml_string(i.add_data_conf)
|
res, adp = parse_toml_string(i.add_data_conf)
|
||||||
if res < 0:
|
if res < 0:
|
||||||
return (-1, "add data conf invalid")
|
return (-1, f"add data conf invalid {adp}")
|
||||||
id = uuid4()
|
id = uuid4()
|
||||||
print(f"RUN {id} INITIATED")
|
print(f"RUN {id} INITIATED")
|
||||||
name = i.name
|
name = i.name
|
||||||
@ -1114,7 +1114,7 @@ def get_all_archived_runners_p(request: DataTablesRequest) -> Tuple[int, RunArch
|
|||||||
# Total count query
|
# Total count query
|
||||||
total_count_query = """
|
total_count_query = """
|
||||||
SELECT COUNT(*) FROM runner_header
|
SELECT COUNT(*) FROM runner_header
|
||||||
WHERE (:search_value = '' OR strat_id LIKE :search_value OR batch_id LIKE :search_value)
|
WHERE (:search_value = '' OR strat_id LIKE :search_value OR batch_id LIKE :search_value OR symbol like :search_value OR name like :search_value)
|
||||||
"""
|
"""
|
||||||
c.execute(total_count_query, {'search_value': f'%{search_value}%'})
|
c.execute(total_count_query, {'search_value': f'%{search_value}%'})
|
||||||
total_count = c.fetchone()[0]
|
total_count = c.fetchone()[0]
|
||||||
@ -1129,7 +1129,7 @@ def get_all_archived_runners_p(request: DataTablesRequest) -> Tuple[int, RunArch
|
|||||||
SUM(profit) OVER (PARTITION BY batch_id) AS batch_profit,
|
SUM(profit) OVER (PARTITION BY batch_id) AS batch_profit,
|
||||||
COUNT(*) OVER (PARTITION BY batch_id) AS batch_count
|
COUNT(*) OVER (PARTITION BY batch_id) AS batch_count
|
||||||
FROM runner_header
|
FROM runner_header
|
||||||
WHERE (:search_value = '' OR strat_id LIKE :search_value OR batch_id LIKE :search_value)
|
WHERE (:search_value = '' OR strat_id LIKE :search_value OR batch_id LIKE :search_value OR symbol like :search_value OR name like :search_value)
|
||||||
),
|
),
|
||||||
InterleavedGroups AS (
|
InterleavedGroups AS (
|
||||||
SELECT *,
|
SELECT *,
|
||||||
@ -1156,7 +1156,7 @@ def get_all_archived_runners_p(request: DataTablesRequest) -> Tuple[int, RunArch
|
|||||||
# Filtered count query
|
# Filtered count query
|
||||||
filtered_count_query = """
|
filtered_count_query = """
|
||||||
SELECT COUNT(*) FROM runner_header
|
SELECT COUNT(*) FROM runner_header
|
||||||
WHERE (:search_value = '' OR strat_id LIKE :search_value OR batch_id LIKE :search_value)
|
WHERE (:search_value = '' OR strat_id LIKE :search_value OR batch_id LIKE :search_value OR symbol like :search_value OR name like :search_value)
|
||||||
"""
|
"""
|
||||||
c.execute(filtered_count_query, {'search_value': f'%{search_value}%'})
|
c.execute(filtered_count_query, {'search_value': f'%{search_value}%'})
|
||||||
filtered_count = c.fetchone()[0]
|
filtered_count = c.fetchone()[0]
|
||||||
@ -1595,7 +1595,7 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
# print(row)
|
# print(row)
|
||||||
res, toml_parsed = parse_toml_string(tomlino)
|
res, toml_parsed = parse_toml_string(tomlino)
|
||||||
if res < 0:
|
if res < 0:
|
||||||
return (-2, "toml invalid")
|
return (-2, f"toml invalid: {toml_parsed}")
|
||||||
|
|
||||||
#print("parsed toml", toml_parsed)
|
#print("parsed toml", toml_parsed)
|
||||||
|
|
||||||
@ -1841,10 +1841,10 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
|
|
||||||
#vracime list, kde pozice 0 je bar indicators, pozice 1 je ticks indicators
|
#vracime list, kde pozice 0 je bar indicators, pozice 1 je ticks indicators
|
||||||
if output == "bar":
|
if output == "bar":
|
||||||
return 0, [output_dict, []]
|
return 0, [output_dict, {}]
|
||||||
#return 0, [new_inds[indicator.name], []]
|
#return 0, [new_inds[indicator.name], []]
|
||||||
else:
|
else:
|
||||||
return 0, [[], output_dict]
|
return 0, [{}, output_dict]
|
||||||
#return 0, [[], new_tick_inds[indicator.name]]
|
#return 0, [[], new_tick_inds[indicator.name]]
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@ -667,14 +667,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group mt-3">
|
<div class="form-group mt-3">
|
||||||
<label for="logHere" class="form-label">Log</label>
|
<label for="logHere" class="form-label">Log</label>
|
||||||
<div id="log-container">
|
<div id="log-container"style="height:700px;border:1px solid black;">
|
||||||
<pre id="log-content"></pre>
|
<!-- <pre id="log-content"></pre> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-primary" id="logRefreshButton" value="Refresh">Refresh</button>
|
<button type="button" class="btn btn-primary" id="logRefreshButton" value="Refresh">Refresh</button>
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
<button type="button" class="btn btn-secondary" id="closeLogModal" data-bs-dismiss="modal">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1166,9 +1166,9 @@
|
|||||||
<!-- <script src="/static/js/archivetables.js?v=1.05"></script> -->
|
<!-- <script src="/static/js/archivetables.js?v=1.05"></script> -->
|
||||||
<!-- archiveTables split into separate files -->
|
<!-- archiveTables split into separate files -->
|
||||||
<script src="/static/js/tables/archivetable/init.js?v=1.12"></script>
|
<script src="/static/js/tables/archivetable/init.js?v=1.12"></script>
|
||||||
<script src="/static/js/tables/archivetable/functions.js?v=1.10"></script>
|
<script src="/static/js/tables/archivetable/functions.js?v=1.11"></script>
|
||||||
<script src="/static/js/tables/archivetable/modals.js?v=1.07"></script>
|
<script src="/static/js/tables/archivetable/modals.js?v=1.07"></script>
|
||||||
<script src="/static/js/tables/archivetable/handlers.js?v=1.09"></script>
|
<script src="/static/js/tables/archivetable/handlers.js?v=1.11"></script>
|
||||||
|
|
||||||
<!-- Runmanager functionality -->
|
<!-- Runmanager functionality -->
|
||||||
<script src="/static/js/tables/runmanager/init.js?v=1.1"></script>
|
<script src="/static/js/tables/runmanager/init.js?v=1.1"></script>
|
||||||
@ -1178,7 +1178,7 @@
|
|||||||
|
|
||||||
<script src="/static/js/livewebsocket.js?v=1.02"></script>
|
<script src="/static/js/livewebsocket.js?v=1.02"></script>
|
||||||
<script src="/static/js/realtimechart.js?v=1.02"></script>
|
<script src="/static/js/realtimechart.js?v=1.02"></script>
|
||||||
<script src="/static/js/mytables.js?v=1.02"></script>
|
<script src="/static/js/mytables.js?v=1.03"></script>
|
||||||
<script src="/static/js/testlist.js?v=1.01"></script>
|
<script src="/static/js/testlist.js?v=1.01"></script>
|
||||||
<script src="/static/js/ml.js?v=1.02"></script>
|
<script src="/static/js/ml.js?v=1.02"></script>
|
||||||
<script src="/static/js/common.js?v=1.01"></script>
|
<script src="/static/js/common.js?v=1.01"></script>
|
||||||
|
|||||||
@ -90,9 +90,55 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
monaco.languages.register({ id: 'python' });
|
monaco.languages.register({ id: 'python' });
|
||||||
monaco.languages.register({ id: 'json' });
|
monaco.languages.register({ id: 'json' });
|
||||||
|
//Register mylogs language
|
||||||
|
monaco.languages.register({ id: 'mylogs' });
|
||||||
// Register the TOML language
|
// Register the TOML language
|
||||||
|
monaco.languages.setLanguageConfiguration('mylogs', {
|
||||||
|
comments: {
|
||||||
|
lineComment: '//', // Adjust if your logs use a different comment symbol
|
||||||
|
},
|
||||||
|
brackets: [['[', ']'], ['{', '}']], // Array and object brackets
|
||||||
|
autoClosingPairs: [
|
||||||
|
{ open: '{', close: '}', notIn: ['string'] },
|
||||||
|
{ open: '"', close: '"', notIn: ['string', 'comment'] },
|
||||||
|
{ open: "'", close: "'", notIn: ['string', 'comment'] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
monaco.languages.setMonarchTokensProvider('mylogs', {
|
||||||
|
tokenizer: {
|
||||||
|
root: [
|
||||||
|
[/#.*/, 'comment'], // Comments (if applicable)
|
||||||
|
|
||||||
|
// Timestamps
|
||||||
|
[/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+/, 'timestamp'],
|
||||||
|
|
||||||
|
// Log Levels
|
||||||
|
[/\b(INFO|DEBUG|WARNING|ERROR|CRITICAL)\b/, 'log-level'],
|
||||||
|
|
||||||
|
// Strings
|
||||||
|
[/".*"/, 'string'],
|
||||||
|
[/'.*'/, 'string'],
|
||||||
|
|
||||||
|
// Key-Value Pairs
|
||||||
|
[/[A-Za-z_]+\s*:/, 'key'],
|
||||||
|
[/-?\d+\.\d+/, 'number.float'], // Floating-point
|
||||||
|
[/-?\d+/, 'number.integer'], // Integers
|
||||||
|
[/\btrue\b/, 'boolean.true'],
|
||||||
|
[/\bfalse\b/, 'boolean.false'],
|
||||||
|
|
||||||
|
// Other Words and Symbols
|
||||||
|
[/[A-Za-z_]+/, 'identifier'],
|
||||||
|
[/[ \t\r\n]+/, 'white'],
|
||||||
|
[/[\[\]{}(),]/, 'delimiter'], // Expand if more delimiters exist
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
monaco.languages.register({ id: 'toml' });
|
monaco.languages.register({ id: 'toml' });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Define the TOML language configuration
|
// Define the TOML language configuration
|
||||||
monaco.languages.setLanguageConfiguration('toml', {
|
monaco.languages.setLanguageConfiguration('toml', {
|
||||||
comments: {
|
comments: {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ let editor_diff_arch1
|
|||||||
let editor_diff_arch2
|
let editor_diff_arch2
|
||||||
var archData = null
|
var archData = null
|
||||||
var batchHeaders = []
|
var batchHeaders = []
|
||||||
|
var editorLog = null
|
||||||
|
|
||||||
function refresh_arch_and_callback(row, callback) {
|
function refresh_arch_and_callback(row, callback) {
|
||||||
//console.log("entering refresh")
|
//console.log("entering refresh")
|
||||||
@ -462,7 +463,7 @@ function display_batch_report(batch_id) {
|
|||||||
|
|
||||||
function refresh_logfile() {
|
function refresh_logfile() {
|
||||||
logfile = $("#logFileSelect").val()
|
logfile = $("#logFileSelect").val()
|
||||||
lines = 700
|
lines = 1200
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url:"/log?lines="+lines+"&logfile="+logfile,
|
url:"/log?lines="+lines+"&logfile="+logfile,
|
||||||
beforeSend: function (xhr) {
|
beforeSend: function (xhr) {
|
||||||
@ -472,13 +473,34 @@ function refresh_logfile() {
|
|||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success:function(response){
|
success:function(response){
|
||||||
|
if (editorLog) {
|
||||||
|
editorLog.dispose();
|
||||||
|
}
|
||||||
if (response.lines.length == 0) {
|
if (response.lines.length == 0) {
|
||||||
$('#log-content').html("no records");
|
value = "no records";
|
||||||
|
// $('#log-content').html("no records");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var escapedLines = response.lines.map(line => escapeHtml(line));
|
//console.log(response.lines)
|
||||||
$('#log-content').html(escapedLines.join('\n'));
|
//var escapedLines = response.lines.map(line => escapeHtml(line));
|
||||||
}
|
value = response.lines.join('\n')
|
||||||
|
// $('#log-content').html(escapedLines.join('\n'));
|
||||||
|
}
|
||||||
|
require(["vs/editor/editor.main"], () => {
|
||||||
|
editorLog = monaco.editor.create(document.getElementById('log-container'), {
|
||||||
|
value: value,
|
||||||
|
language: 'mylogs',
|
||||||
|
theme: 'tomlTheme-dark',
|
||||||
|
automaticLayout: true,
|
||||||
|
readOnly: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Focus at the end of the file:
|
||||||
|
const model = editorLog.getModel();
|
||||||
|
const lastLineNumber = model.getLineCount();
|
||||||
|
const lastLineColumn = model.getLineMaxColumn(lastLineNumber);
|
||||||
|
editorLog.setPosition({ lineNumber: lastLineNumber, column: lastLineColumn });
|
||||||
|
editorLog.revealPosition({ lineNumber: lastLineNumber, column: lastLineColumn });
|
||||||
},
|
},
|
||||||
error: function(xhr, status, error) {
|
error: function(xhr, status, error) {
|
||||||
var err = eval("(" + xhr.responseText + ")");
|
var err = eval("(" + xhr.responseText + ")");
|
||||||
|
|||||||
@ -265,8 +265,8 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
$('#diff_first').text(record1.name);
|
$('#diff_first').text(record1.name);
|
||||||
$('#diff_second').text(record2.name);
|
$('#diff_second').text(record2.name);
|
||||||
$('#diff_first_id').text(data1.id);
|
$('#diff_first_id').text(data1.id + ' Batch: ' + data1.batch_id);
|
||||||
$('#diff_second_id').text(data2.id);
|
$('#diff_second_id').text(data2.id + ' Batch: ' + data2.batch_id);
|
||||||
|
|
||||||
//monaco
|
//monaco
|
||||||
require(["vs/editor/editor.main"], () => {
|
require(["vs/editor/editor.main"], () => {
|
||||||
@ -358,8 +358,13 @@ $(document).ready(function () {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#closeLogModal').click(function () {
|
||||||
|
editorLog.dispose()
|
||||||
|
});
|
||||||
|
|
||||||
//button to query log
|
//button to query log
|
||||||
$('#logRefreshButton').click(function () {
|
$('#logRefreshButton').click(function () {
|
||||||
|
editorLog.dispose()
|
||||||
refresh_logfile()
|
refresh_logfile()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -35,40 +35,62 @@ class StrategyClassicSL(Strategy):
|
|||||||
|
|
||||||
max_sum_profit_to_quit_rel = safe_get(self.state.vars, "max_sum_profit_to_quit_rel", None)
|
max_sum_profit_to_quit_rel = safe_get(self.state.vars, "max_sum_profit_to_quit_rel", None)
|
||||||
max_sum_loss_to_quit_rel = safe_get(self.state.vars, "max_sum_loss_to_quit_rel", None)
|
max_sum_loss_to_quit_rel = safe_get(self.state.vars, "max_sum_loss_to_quit_rel", None)
|
||||||
|
#load typ direktivy hard/soft cutoff
|
||||||
|
hard_cutoff = safe_get(self.state.vars, "hard_cutoff", False)
|
||||||
|
|
||||||
rel_profit = round(float(np.sum(self.state.rel_profit_cum)),5)
|
rel_profit = round(float(np.sum(self.state.rel_profit_cum)),5)
|
||||||
if max_sum_profit_to_quit_rel is not None:
|
if max_sum_profit_to_quit_rel is not None:
|
||||||
if rel_profit >= float(max_sum_profit_to_quit_rel):
|
if rel_profit >= float(max_sum_profit_to_quit_rel):
|
||||||
self.state.ilog(e=f"QUITTING MAX SUM REL PROFIT REACHED {max_sum_profit_to_quit_rel=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}")
|
msg = f"QUITTING {hard_cutoff=} MAX SUM REL PROFIT REACHED {max_sum_profit_to_quit_rel=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}"
|
||||||
|
printanyway(msg)
|
||||||
|
self.state.ilog(e=msg)
|
||||||
self.state.vars.pending = "max_sum_profit_to_quit_rel"
|
self.state.vars.pending = "max_sum_profit_to_quit_rel"
|
||||||
if self.mode not in [Mode.BT, Mode.PREP]:
|
if self.mode not in [Mode.BT, Mode.PREP]:
|
||||||
send_to_telegram(f"QUITTING MAX SUM REL PROFIT REACHED {max_sum_profit_to_quit_rel=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}")
|
send_to_telegram(msg)
|
||||||
self.signal_stop = True
|
if hard_cutoff:
|
||||||
|
self.hard_stop = True
|
||||||
|
else:
|
||||||
|
self.soft_stop = True
|
||||||
return True
|
return True
|
||||||
if max_sum_loss_to_quit_rel is not None:
|
if max_sum_loss_to_quit_rel is not None:
|
||||||
if rel_profit < 0 and rel_profit <= float(max_sum_loss_to_quit_rel):
|
if rel_profit < 0 and rel_profit <= float(max_sum_loss_to_quit_rel):
|
||||||
self.state.ilog(e=f"QUITTING MAX SUM REL LOSS REACHED {max_sum_loss_to_quit_rel=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}")
|
msg=f"QUITTING {hard_cutoff=} MAX SUM REL LOSS REACHED {max_sum_loss_to_quit_rel=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}"
|
||||||
|
printanyway(msg)
|
||||||
|
self.state.ilog(e=msg)
|
||||||
self.state.vars.pending = "max_sum_loss_to_quit_rel"
|
self.state.vars.pending = "max_sum_loss_to_quit_rel"
|
||||||
if self.mode not in [Mode.BT, Mode.PREP]:
|
if self.mode not in [Mode.BT, Mode.PREP]:
|
||||||
send_to_telegram(f"QUITTING MAX SUM REL LOSS REACHED {max_sum_loss_to_quit_rel=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}")
|
send_to_telegram(msg)
|
||||||
self.signal_stop = True
|
if hard_cutoff:
|
||||||
|
self.hard_stop = True
|
||||||
|
else:
|
||||||
|
self.soft_stop = True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if max_sum_profit_to_quit is not None:
|
if max_sum_profit_to_quit is not None:
|
||||||
if float(self.state.profit) >= float(max_sum_profit_to_quit):
|
if float(self.state.profit) >= float(max_sum_profit_to_quit):
|
||||||
self.state.ilog(e=f"QUITTING MAX SUM ABS PROFIT REACHED {max_sum_profit_to_quit=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}")
|
msg = f"QUITTING {hard_cutoff=} MAX SUM ABS PROFIT REACHED {max_sum_profit_to_quit=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}"
|
||||||
|
printanyway(msg)
|
||||||
|
self.state.ilog(e=msg)
|
||||||
self.state.vars.pending = "max_sum_profit_to_quit"
|
self.state.vars.pending = "max_sum_profit_to_quit"
|
||||||
if self.mode not in [Mode.BT, Mode.PREP]:
|
if self.mode not in [Mode.BT, Mode.PREP]:
|
||||||
send_to_telegram(f"QUITTING MAX SUM ABS PROFIT REACHED {max_sum_profit_to_quit=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}")
|
send_to_telegram(msg)
|
||||||
self.signal_stop = True
|
if hard_cutoff:
|
||||||
|
self.hard_stop = True
|
||||||
|
else:
|
||||||
|
self.soft_stop = True
|
||||||
return True
|
return True
|
||||||
if max_sum_loss_to_quit is not None:
|
if max_sum_loss_to_quit is not None:
|
||||||
if float(self.state.profit) < 0 and float(self.state.profit) <= float(max_sum_loss_to_quit):
|
if float(self.state.profit) < 0 and float(self.state.profit) <= float(max_sum_loss_to_quit):
|
||||||
self.state.ilog(e=f"QUITTING MAX SUM ABS LOSS REACHED {max_sum_loss_to_quit=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}")
|
msg = f"QUITTING {hard_cutoff=} MAX SUM ABS LOSS REACHED {max_sum_loss_to_quit=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}"
|
||||||
|
printanyway(msg)
|
||||||
|
self.state.ilog(e=msg)
|
||||||
self.state.vars.pending = "max_sum_loss_to_quit"
|
self.state.vars.pending = "max_sum_loss_to_quit"
|
||||||
if self.mode not in [Mode.BT, Mode.PREP]:
|
if self.mode not in [Mode.BT, Mode.PREP]:
|
||||||
send_to_telegram(f"QUITTING MAX SUM ABS LOSS REACHED {max_sum_loss_to_quit=} {self.state.profit=} {rel_profit=} relprofits:{str(self.state.rel_profit_cum)}")
|
send_to_telegram(msg)
|
||||||
self.signal_stop = True
|
if hard_cutoff:
|
||||||
|
self.hard_stop = True
|
||||||
|
else:
|
||||||
|
self.soft_stop = True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@ -414,7 +436,7 @@ class StrategyClassicSL(Strategy):
|
|||||||
populate_all_indicators(item, self.state)
|
populate_all_indicators(item, self.state)
|
||||||
|
|
||||||
#pro přípravu dat next nevoláme
|
#pro přípravu dat next nevoláme
|
||||||
if self.mode == Mode.PREP:
|
if self.mode == Mode.PREP or self.soft_stop:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.next(item, self.state)
|
self.next(item, self.state)
|
||||||
|
|||||||
@ -80,7 +80,8 @@ class Strategy:
|
|||||||
self.pe = pe
|
self.pe = pe
|
||||||
self.se = se
|
self.se = se
|
||||||
#signal stop - internal
|
#signal stop - internal
|
||||||
self.signal_stop = False
|
self.hard_stop = False #indikuje hard stop, tedy vypnuti strategie
|
||||||
|
self.soft_stop = False #indikuje soft stop (napr. při dosažení max zisku/ztráty), tedy pokracovani strategie, vytvareni dat, jen bez obchodu
|
||||||
|
|
||||||
#prdelat queue na dynamic - podle toho jak bud uchtit pracovat s multiresolutions
|
#prdelat queue na dynamic - podle toho jak bud uchtit pracovat s multiresolutions
|
||||||
#zatim jen jedna q1
|
#zatim jen jedna q1
|
||||||
@ -433,7 +434,7 @@ class Strategy:
|
|||||||
#printnow(current_thread().name, "Items waiting in queue:", self.q1.qsize())
|
#printnow(current_thread().name, "Items waiting in queue:", self.q1.qsize())
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
#check internal signals - for profit/loss optim etc - valid for runner
|
#check internal signals - for profit/loss optim etc - valid for runner
|
||||||
if self.signal_stop:
|
if self.hard_stop:
|
||||||
print(current_thread().name, "Stopping signal - internal")
|
print(current_thread().name, "Stopping signal - internal")
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -454,7 +455,7 @@ class Strategy:
|
|||||||
if item == "last" or self.se.is_set():
|
if item == "last" or self.se.is_set():
|
||||||
print(current_thread().name, "stopping")
|
print(current_thread().name, "stopping")
|
||||||
break
|
break
|
||||||
elif self.signal_stop:
|
elif self.hard_stop:
|
||||||
print(current_thread().name, "Stopping signal - internal")
|
print(current_thread().name, "Stopping signal - internal")
|
||||||
break
|
break
|
||||||
elif self.pe.is_set():
|
elif self.pe.is_set():
|
||||||
|
|||||||
@ -5,99 +5,108 @@ from v2realbot.utils.utils import slice_dict_lists,zoneUTC,safe_get, AttributeDi
|
|||||||
#id = "b11c66d9-a9b6-475a-9ac1-28b11e1b4edf"
|
#id = "b11c66d9-a9b6-475a-9ac1-28b11e1b4edf"
|
||||||
#state = AttributeDict(vars={})
|
#state = AttributeDict(vars={})
|
||||||
from rich import print
|
from rich import print
|
||||||
|
from traceback import format_exc
|
||||||
|
|
||||||
def attach_previous_data(state):
|
def attach_previous_data(state):
|
||||||
"""""
|
"""""
|
||||||
Attaches data from previous runner of the same batch.
|
Attaches data from previous runner of the same batch.
|
||||||
"""""
|
"""""
|
||||||
print("ATTACHING PREVIOUS DATA")
|
print("ATTACHING PREVIOUS DATA")
|
||||||
runner : Runner
|
try:
|
||||||
#get batch_id of current runer
|
runner : Runner
|
||||||
res, runner = cs.get_runner(state.runner_id)
|
#get batch_id of current runer
|
||||||
if res < 0:
|
res, runner = cs.get_runner(state.runner_id)
|
||||||
if runner.batch_id is None:
|
if res < 0:
|
||||||
print(f"No batch_id found for runner {runner.id}")
|
if runner.batch_id is None:
|
||||||
|
print(f"No batch_id found for runner {runner.id}")
|
||||||
|
else:
|
||||||
|
print(f"Couldnt get previous runner {state.runner_id} error: {runner}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
batch_id = runner.batch_id
|
||||||
|
#batch_id = "6a6b0bcf"
|
||||||
|
res, runner_ids =cs.get_archived_runnerslist_byBatchID(batch_id, "desc")
|
||||||
|
if res < 0:
|
||||||
|
msg = f"error whne fetching runners of batch {batch_id} {runner_ids}"
|
||||||
|
print(msg)
|
||||||
|
return None
|
||||||
|
|
||||||
|
if runner_ids is None or len(runner_ids) == 0:
|
||||||
|
print(f"NO runners found for batch {batch_id} {runner_ids}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
last_runner = runner_ids[0]
|
||||||
|
print("Previous runner identified:", last_runner)
|
||||||
|
|
||||||
|
#get archived header - to get transferables
|
||||||
|
runner_header : RunArchive = None
|
||||||
|
res, runner_header = cs.get_archived_runner_header_byID(last_runner)
|
||||||
|
if res < 0:
|
||||||
|
print(f"Error when fetching runner header {last_runner}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
state.vars["transferables"] = runner_header.transferables
|
||||||
|
print("INITIALIZED transferables", state.vars["transferables"])
|
||||||
|
|
||||||
|
|
||||||
|
#get details from the runner
|
||||||
|
print(f"Fetching runner details of {last_runner}")
|
||||||
|
res, val = cs.get_archived_runner_details_byID(last_runner)
|
||||||
|
if res < 0:
|
||||||
|
print(f"no archived runner {last_runner}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
detail = RunArchiveDetail(**val)
|
||||||
|
#print("toto jsme si dotahnuli", detail.bars)
|
||||||
|
|
||||||
|
if len(detail.bars["time"]) == 0:
|
||||||
|
print(f"no bars for runner {last_runner}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# from stratvars directives
|
||||||
|
attach_previous_bar_data = safe_get(state.vars, "attach_previous_bar_data", 50)
|
||||||
|
attach_previous_tick_data = safe_get(state.vars, "attach_previous_tick_data", None)
|
||||||
|
|
||||||
|
#indicators datetime utc
|
||||||
|
indicators = slice_dict_lists(d=detail.indicators[0],last_item=attach_previous_bar_data, time_to_datetime=True)
|
||||||
|
|
||||||
|
#time -datetime utc, updated - timestamp float
|
||||||
|
bars = slice_dict_lists(d=detail.bars, last_item=attach_previous_bar_data, time_to_datetime=True)
|
||||||
|
|
||||||
|
cbar_ids = {}
|
||||||
|
#zarovname tick spolu s bar daty
|
||||||
|
if attach_previous_tick_data is None:
|
||||||
|
oldest_timestamp = bars["updated"][0]
|
||||||
|
|
||||||
|
#returns only values older that oldest_timestamp
|
||||||
|
cbar_inds = filter_timeseries_by_timestamp(detail.indicators[1], oldest_timestamp)
|
||||||
else:
|
else:
|
||||||
print(f"Couldnt get previous runner {state.runner_id} error: {runner}")
|
cbar_inds = slice_dict_lists(d=detail.indicators[1],last_item=attach_previous_tick_data)
|
||||||
|
|
||||||
|
#USE these as INITs - TADY SI TO JESTE ZASTAVIT a POROVNAT
|
||||||
|
#print("state.indicatorsL", state.indicators, "NEW:", indicators)
|
||||||
|
state.indicators = AttributeDict(**indicators)
|
||||||
|
print("transfered indicators:", len(state.indicators["time"]))
|
||||||
|
#print("state.bars", state.bars, "NEW:", bars)
|
||||||
|
state.bars = AttributeDict(bars)
|
||||||
|
print("transfered bars:", len(state.bars["time"]))
|
||||||
|
#print("state.cbar_indicators", state.cbar_indicators, "NEW:", cbar_inds)
|
||||||
|
state.cbar_indicators = AttributeDict(cbar_inds)
|
||||||
|
print("transfered ticks:", len(state.cbar_indicators["time"]))
|
||||||
|
|
||||||
|
print("TRANSFERABLEs INITIALIZED")
|
||||||
|
#bars
|
||||||
|
#transferable_state_vars = ["martingale", "batch_profit"]
|
||||||
|
#1. pri initu se tyto klice v state vars se namapuji do ext_data ext_data["transferrables"]["martingale"] = state.vars["martingale"]
|
||||||
|
#2. pri transferu se vse z ext_data["trasferrables"] dá do stejnénné state.vars["martingale"]
|
||||||
|
#3. na konci dne se uloží do sloupce transferables v RunArchive
|
||||||
|
|
||||||
|
#pridavame dailyBars z extData
|
||||||
|
# if hasattr(detail, "ext_data") and "dailyBars" in detail.ext_data:
|
||||||
|
# state.dailyBars = detail.ext_data["dailyBars"]
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
print(str(e)+format_exc())
|
||||||
return None
|
return None
|
||||||
|
|
||||||
batch_id = runner.batch_id
|
|
||||||
#batch_id = "6a6b0bcf"
|
|
||||||
res, runner_ids =cs.get_archived_runnerslist_byBatchID(batch_id, "desc")
|
|
||||||
if res < 0:
|
|
||||||
msg = f"error whne fetching runners of batch {batch_id} {runner_ids}"
|
|
||||||
print(msg)
|
|
||||||
return None
|
|
||||||
|
|
||||||
if runner_ids is None or len(runner_ids) == 0:
|
|
||||||
print(f"NO runners found for batch {batch_id} {runner_ids}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
last_runner = runner_ids[0]
|
|
||||||
print("Previous runner identified:", last_runner)
|
|
||||||
|
|
||||||
#get archived header - to get transferables
|
|
||||||
runner_header : RunArchive = None
|
|
||||||
res, runner_header = cs.get_archived_runner_header_byID(last_runner)
|
|
||||||
if res < 0:
|
|
||||||
print(f"Error when fetching runner header {last_runner}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
state.vars["transferables"] = runner_header.transferables
|
|
||||||
print("INITIALIZED transferables", state.vars["transferables"])
|
|
||||||
|
|
||||||
|
|
||||||
#get details from the runner
|
|
||||||
print(f"Fetching runner details of {last_runner}")
|
|
||||||
res, val = cs.get_archived_runner_details_byID(last_runner)
|
|
||||||
if res < 0:
|
|
||||||
print(f"no archived runner {last_runner}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
detail = RunArchiveDetail(**val)
|
|
||||||
#print("toto jsme si dotahnuli", detail.bars)
|
|
||||||
|
|
||||||
# from stratvars directives
|
|
||||||
attach_previous_bar_data = safe_get(state.vars, "attach_previous_bar_data", 50)
|
|
||||||
attach_previous_tick_data = safe_get(state.vars, "attach_previous_tick_data", None)
|
|
||||||
|
|
||||||
#indicators datetime utc
|
|
||||||
indicators = slice_dict_lists(d=detail.indicators[0],last_item=attach_previous_bar_data, time_to_datetime=True)
|
|
||||||
|
|
||||||
#time -datetime utc, updated - timestamp float
|
|
||||||
bars = slice_dict_lists(d=detail.bars, last_item=attach_previous_bar_data, time_to_datetime=True)
|
|
||||||
|
|
||||||
#zarovname tick spolu s bar daty
|
|
||||||
if attach_previous_tick_data is None:
|
|
||||||
oldest_timestamp = bars["updated"][0]
|
|
||||||
|
|
||||||
#returns only values older that oldest_timestamp
|
|
||||||
cbar_inds = filter_timeseries_by_timestamp(detail.indicators[1], oldest_timestamp)
|
|
||||||
else:
|
|
||||||
cbar_inds = slice_dict_lists(d=detail.indicators[1],last_item=attach_previous_tick_data)
|
|
||||||
|
|
||||||
#USE these as INITs - TADY SI TO JESTE ZASTAVIT a POROVNAT
|
|
||||||
#print("state.indicatorsL", state.indicators, "NEW:", indicators)
|
|
||||||
state.indicators = AttributeDict(**indicators)
|
|
||||||
print("transfered indicators:", len(state.indicators["time"]))
|
|
||||||
#print("state.bars", state.bars, "NEW:", bars)
|
|
||||||
state.bars = AttributeDict(bars)
|
|
||||||
print("transfered bars:", len(state.bars["time"]))
|
|
||||||
#print("state.cbar_indicators", state.cbar_indicators, "NEW:", cbar_inds)
|
|
||||||
state.cbar_indicators = AttributeDict(cbar_inds)
|
|
||||||
print("transfered ticks:", len(state.cbar_indicators["time"]))
|
|
||||||
|
|
||||||
print("TRANSFERABLEs INITIALIZED")
|
|
||||||
#bars
|
|
||||||
#transferable_state_vars = ["martingale", "batch_profit"]
|
|
||||||
#1. pri initu se tyto klice v state vars se namapuji do ext_data ext_data["transferrables"]["martingale"] = state.vars["martingale"]
|
|
||||||
#2. pri transferu se vse z ext_data["trasferrables"] dá do stejnénné state.vars["martingale"]
|
|
||||||
#3. na konci dne se uloží do sloupce transferables v RunArchive
|
|
||||||
|
|
||||||
#pridavame dailyBars z extData
|
|
||||||
# if hasattr(detail, "ext_data") and "dailyBars" in detail.ext_data:
|
|
||||||
# state.dailyBars = detail.ext_data["dailyBars"]
|
|
||||||
return
|
|
||||||
|
|
||||||
# if __name__ == "__main__":
|
# if __name__ == "__main__":
|
||||||
# attach_previous_data(state)
|
# attach_previous_data(state)
|
||||||
@ -78,7 +78,7 @@ def execute_signal_generator(state, data, name):
|
|||||||
last_update=datetime.fromtimestamp(state.time).astimezone(zoneNY),
|
last_update=datetime.fromtimestamp(state.time).astimezone(zoneNY),
|
||||||
status=TradeStatus.READY,
|
status=TradeStatus.READY,
|
||||||
generated_by=name,
|
generated_by=name,
|
||||||
size=multiplier*state.vars.chunk,
|
size=int(multiplier*state.vars.chunk),
|
||||||
size_multiplier = multiplier,
|
size_multiplier = multiplier,
|
||||||
direction=TradeDirection.LONG,
|
direction=TradeDirection.LONG,
|
||||||
entry_price=None,
|
entry_price=None,
|
||||||
@ -90,7 +90,7 @@ def execute_signal_generator(state, data, name):
|
|||||||
last_update=datetime.fromtimestamp(state.time).astimezone(zoneNY),
|
last_update=datetime.fromtimestamp(state.time).astimezone(zoneNY),
|
||||||
status=TradeStatus.READY,
|
status=TradeStatus.READY,
|
||||||
generated_by=name,
|
generated_by=name,
|
||||||
size=multiplier*state.vars.chunk,
|
size=int(multiplier*state.vars.chunk),
|
||||||
size_multiplier = multiplier,
|
size_multiplier = multiplier,
|
||||||
direction=TradeDirection.SHORT,
|
direction=TradeDirection.SHORT,
|
||||||
entry_price=None,
|
entry_price=None,
|
||||||
|
|||||||
@ -151,13 +151,17 @@ def get_multiplier(state: StrategyState, data, signaloptions: dict, direction: T
|
|||||||
|
|
||||||
#pocet ztrátových obchodů v řadě mi udává multiplikátor (0 - 1, 1 ztráta 2x, 3 v řadě - 4x atp.)
|
#pocet ztrátových obchodů v řadě mi udává multiplikátor (0 - 1, 1 ztráta 2x, 3 v řadě - 4x atp.)
|
||||||
if martingale_enabled:
|
if martingale_enabled:
|
||||||
|
|
||||||
|
#martingale base - základ umocňování - klasicky 2
|
||||||
|
base = float(utls.safe_get(options, "martingale_base", 2))
|
||||||
|
#pocet aktuálních konsekutivních ztrát
|
||||||
cont_loss_series_cnt = state.vars["transferables"]["martingale"]["cont_loss_series_cnt"]
|
cont_loss_series_cnt = state.vars["transferables"]["martingale"]["cont_loss_series_cnt"]
|
||||||
if cont_loss_series_cnt == 0:
|
if cont_loss_series_cnt == 0:
|
||||||
multiplier = 1
|
multiplier = 1
|
||||||
else:
|
else:
|
||||||
multiplier = 2 ** cont_loss_series_cnt
|
multiplier = base ** cont_loss_series_cnt
|
||||||
state.ilog(lvl=1,e=f"SIZER - MARTINGALE {multiplier}", options=options, time=state.time, cont_loss_series_cnt=cont_loss_series_cnt)
|
state.ilog(lvl=1,e=f"SIZER - MARTINGALE {multiplier}", options=options, time=state.time, cont_loss_series_cnt=cont_loss_series_cnt)
|
||||||
|
|
||||||
if (martingale_enabled is False and multiplier > 1) or multiplier <= 0:
|
if (martingale_enabled is False and multiplier > 1) or multiplier <= 0:
|
||||||
state.ilog(lvl=1,e=f"SIZER - Mame nekde problem MULTIPLIER mimo RANGE ERROR {multiplier}", options=options, time=state.time)
|
state.ilog(lvl=1,e=f"SIZER - Mame nekde problem MULTIPLIER mimo RANGE ERROR {multiplier}", options=options, time=state.time)
|
||||||
multiplier = 1
|
multiplier = 1
|
||||||
|
|||||||
@ -678,8 +678,9 @@ def parse_toml_string(tomlst: str):
|
|||||||
try:
|
try:
|
||||||
tomlst = tomli.loads(tomlst)
|
tomlst = tomli.loads(tomlst)
|
||||||
except tomli.TOMLDecodeError as e:
|
except tomli.TOMLDecodeError as e:
|
||||||
print("Not valid TOML.", str(e))
|
msg = f"Not valid TOML: " + str(e)
|
||||||
return (-1, None)
|
richprint(msg)
|
||||||
|
return (-1, msg)
|
||||||
return (0, dict_replace_value(tomlst,"None",None))
|
return (0, dict_replace_value(tomlst,"None",None))
|
||||||
|
|
||||||
#class to persist
|
#class to persist
|
||||||
|
|||||||
Reference in New Issue
Block a user