Add typed options review form presets by source.
Pure options and hedge plans use separate strategy/entry selects, with auto-filled direction and PnL result including breakeven. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -10,6 +10,19 @@
|
|||||||
options_options: "期期对冲记录",
|
options_options: "期期对冲记录",
|
||||||
perp_options: "永期对冲记录",
|
perp_options: "永期对冲记录",
|
||||||
};
|
};
|
||||||
|
var FORM_PRESETS = {
|
||||||
|
option_spot: {
|
||||||
|
strategy: ["顺势", "反转"],
|
||||||
|
direction: ["多", "空"],
|
||||||
|
entry: ["假突破", "结构突破"],
|
||||||
|
},
|
||||||
|
hedge: {
|
||||||
|
strategy: ["横盘", "趋势"],
|
||||||
|
direction: ["多", "空"],
|
||||||
|
entry: ["横盘博弈方向", "趋势对冲止损"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var RESULT_OPTIONS = ["盈利", "亏损", "持平"];
|
||||||
var activeSource = "option_spot";
|
var activeSource = "option_spot";
|
||||||
var currentTradeId = null;
|
var currentTradeId = null;
|
||||||
var draftId = "";
|
var draftId = "";
|
||||||
@@ -80,6 +93,81 @@
|
|||||||
loadStats();
|
loadStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isHedgeSource(sourceType) {
|
||||||
|
return sourceType === "options_options" || sourceType === "perp_options";
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillSelect(el, options, placeholder) {
|
||||||
|
if (!el) return;
|
||||||
|
var keep = el.value;
|
||||||
|
el.innerHTML = "";
|
||||||
|
var first = document.createElement("option");
|
||||||
|
first.value = "";
|
||||||
|
first.textContent = placeholder || "";
|
||||||
|
el.appendChild(first);
|
||||||
|
(options || []).forEach(function (v) {
|
||||||
|
var opt = document.createElement("option");
|
||||||
|
opt.value = v;
|
||||||
|
opt.textContent = v;
|
||||||
|
el.appendChild(opt);
|
||||||
|
});
|
||||||
|
if (keep) setSelectValue(el, keep);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSelectValue(el, value) {
|
||||||
|
if (!el) return;
|
||||||
|
var v = value == null ? "" : String(value);
|
||||||
|
if (!v) {
|
||||||
|
el.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var found = false;
|
||||||
|
for (var i = 0; i < el.options.length; i++) {
|
||||||
|
if (el.options[i].value === v) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
var opt = document.createElement("option");
|
||||||
|
opt.value = v;
|
||||||
|
opt.textContent = v;
|
||||||
|
el.appendChild(opt);
|
||||||
|
}
|
||||||
|
el.value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyFormPresets(sourceType) {
|
||||||
|
var preset = isHedgeSource(sourceType) ? FORM_PRESETS.hedge : FORM_PRESETS.option_spot;
|
||||||
|
fillSelect($("or-f-strategy"), preset.strategy, "策略标签");
|
||||||
|
fillSelect($("or-f-direction"), preset.direction, "方向判断");
|
||||||
|
fillSelect($("or-f-entry"), preset.entry, "入场逻辑");
|
||||||
|
fillSelect($("or-f-result"), RESULT_OPTIONS, "结果标签");
|
||||||
|
}
|
||||||
|
|
||||||
|
function autoDirection(t) {
|
||||||
|
if (!t) return "";
|
||||||
|
if (isHedgeSource(t.source_type)) {
|
||||||
|
var d = String(t.direction || "").trim().toLowerCase();
|
||||||
|
if (d === "long" || d === "buy" || d === "多") return "多";
|
||||||
|
if (d === "short" || d === "sell" || d === "空") return "空";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
var ot = String(t.opt_type || "").trim().toUpperCase();
|
||||||
|
if (ot === "C" || ot === "CALL") return "多";
|
||||||
|
if (ot === "P" || ot === "PUT") return "空";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function autoResultTag(pnl) {
|
||||||
|
if (pnl == null || pnl === "") return "";
|
||||||
|
var n = Number(pnl);
|
||||||
|
if (Number.isNaN(n)) return "";
|
||||||
|
if (n > 0) return "盈利";
|
||||||
|
if (n < 0) return "亏损";
|
||||||
|
return "持平";
|
||||||
|
}
|
||||||
|
|
||||||
function setActiveTab(source) {
|
function setActiveTab(source) {
|
||||||
activeSource = source || "option_spot";
|
activeSource = source || "option_spot";
|
||||||
document.querySelectorAll(".or-tab").forEach(function (btn) {
|
document.querySelectorAll(".or-tab").forEach(function (btn) {
|
||||||
@@ -87,6 +175,7 @@
|
|||||||
});
|
});
|
||||||
var title = $("or-list-title");
|
var title = $("or-list-title");
|
||||||
if (title) title.textContent = TAB_LABELS[activeSource] || "记录";
|
if (title) title.textContent = TAB_LABELS[activeSource] || "记录";
|
||||||
|
applyFormPresets(activeSource);
|
||||||
hideJournalForm();
|
hideJournalForm();
|
||||||
reloadAll();
|
reloadAll();
|
||||||
}
|
}
|
||||||
@@ -429,6 +518,7 @@
|
|||||||
|
|
||||||
function fillForm(t) {
|
function fillForm(t) {
|
||||||
var e = t.entry || {};
|
var e = t.entry || {};
|
||||||
|
applyFormPresets(t.source_type || activeSource);
|
||||||
($("or-trade-id") || {}).value = String(t.id || "");
|
($("or-trade-id") || {}).value = String(t.id || "");
|
||||||
($("or-f-open") || {}).value = toLocalInput(t.opened_at);
|
($("or-f-open") || {}).value = toLocalInput(t.opened_at);
|
||||||
($("or-f-close") || {}).value = toLocalInput(t.closed_at);
|
($("or-f-close") || {}).value = toLocalInput(t.closed_at);
|
||||||
@@ -439,12 +529,12 @@
|
|||||||
: (t.source_label || "") + (t.plan_close_reason ? " · " + t.plan_close_reason : "");
|
: (t.source_label || "") + (t.plan_close_reason ? " · " + t.plan_close_reason : "");
|
||||||
($("or-f-pnl") || {}).value = fmtPnl(t.realized_pnl_total);
|
($("or-f-pnl") || {}).value = fmtPnl(t.realized_pnl_total);
|
||||||
($("or-f-hold") || {}).value = fmtHold(t.hold_seconds);
|
($("or-f-hold") || {}).value = fmtHold(t.hold_seconds);
|
||||||
($("or-f-strategy") || {}).value = e.strategy_tag || "";
|
setSelectValue($("or-f-strategy"), e.strategy_tag || "");
|
||||||
($("or-f-direction") || {}).value = e.direction_view || t.direction || "";
|
setSelectValue($("or-f-direction"), e.direction_view || autoDirection(t));
|
||||||
($("or-f-exit") || {}).value = e.exit_reason || t.plan_close_reason || "";
|
($("or-f-exit") || {}).value = e.exit_reason || t.plan_close_reason || "";
|
||||||
($("or-f-followed") || {}).value = e.followed_plan || "";
|
($("or-f-followed") || {}).value = e.followed_plan || "";
|
||||||
($("or-f-result") || {}).value = e.result_tag || "";
|
setSelectValue($("or-f-result"), e.result_tag || autoResultTag(t.realized_pnl_total));
|
||||||
($("or-f-entry") || {}).value = e.entry_logic || "";
|
setSelectValue($("or-f-entry"), e.entry_logic || "");
|
||||||
($("or-f-note") || {}).value = e.note || "";
|
($("or-f-note") || {}).value = e.note || "";
|
||||||
setMoodTags(e.mistake_tags);
|
setMoodTags(e.mistake_tags);
|
||||||
|
|
||||||
@@ -533,7 +623,7 @@
|
|||||||
}
|
}
|
||||||
var strategy = (($("or-f-strategy") || {}).value || "").trim();
|
var strategy = (($("or-f-strategy") || {}).value || "").trim();
|
||||||
if (!strategy) {
|
if (!strategy) {
|
||||||
alert("请填写策略标签");
|
alert("请选择策略标签");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var payload = {
|
var payload = {
|
||||||
|
|||||||
@@ -83,8 +83,12 @@
|
|||||||
<input type="text" id="or-f-hold" placeholder="持有时长" readonly>
|
<input type="text" id="or-f-hold" placeholder="持有时长" readonly>
|
||||||
</div>
|
</div>
|
||||||
<div class="or-form-grid2">
|
<div class="or-form-grid2">
|
||||||
<input type="text" id="or-f-strategy" placeholder="策略标签" required>
|
<select id="or-f-strategy" title="策略标签" required>
|
||||||
<input type="text" id="or-f-direction" placeholder="方向判断">
|
<option value="">策略标签</option>
|
||||||
|
</select>
|
||||||
|
<select id="or-f-direction" title="方向判断">
|
||||||
|
<option value="">方向判断</option>
|
||||||
|
</select>
|
||||||
<select id="or-f-exit" title="离场原因">
|
<select id="or-f-exit" title="离场原因">
|
||||||
<option value="">离场原因</option>
|
<option value="">离场原因</option>
|
||||||
<option value="止盈">止盈</option>
|
<option value="止盈">止盈</option>
|
||||||
@@ -100,9 +104,16 @@
|
|||||||
<option value="否">否</option>
|
<option value="否">否</option>
|
||||||
<option value="部分">部分</option>
|
<option value="部分">部分</option>
|
||||||
</select>
|
</select>
|
||||||
<input type="text" id="or-f-result" placeholder="结果标签">
|
<select id="or-f-result" title="结果标签">
|
||||||
|
<option value="">结果标签</option>
|
||||||
|
<option value="盈利">盈利</option>
|
||||||
|
<option value="亏损">亏损</option>
|
||||||
|
<option value="持平">持平</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<textarea id="or-f-entry" rows="2" placeholder="入场逻辑" style="width:100%;margin-bottom:6px;box-sizing:border-box"></textarea>
|
<select id="or-f-entry" title="入场逻辑" style="width:100%;margin-bottom:6px;box-sizing:border-box">
|
||||||
|
<option value="">入场逻辑</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
<input type="hidden" id="journal-draft-id" value="">
|
<input type="hidden" id="journal-draft-id" value="">
|
||||||
<div class="journal-upload-slots" id="or-upload-slots">
|
<div class="journal-upload-slots" id="or-upload-slots">
|
||||||
@@ -168,4 +179,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/options_review.js?v=6"></script>
|
<script src="/static/options_review.js?v=7"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user