datoria tehnica: garda pe dash, si PChart intr-un singur loc
Garda: `Level(p, text, color, "left")` punea tacut "left" in `dash` in loc de `label_at`, iar SVG-ul iesea fara linie punctata si fara nicio eroare - trei agenti au pierdut timp pe asta pe 13.09. Acum `__post_init__` crapa cu mesaj care spune ce argument voiai. Verificat pe cazurile valide si pe cele doua gresite. PChart: era copiat in cinci generatoare, iar copiile divergisera - toate cinci aveau hash-uri diferite si patru pastrau `spread()` cel vechi. Nucleul comun trece in gen/pchart.py; 385 de linii sterse, 11 adaugate. az_executie.py isi pastreaza PChart-ul: varianta lui calculeaza mediile dintr-un istoric dinainte de bara 0 si si le deseneaza singura. Unirea celor doua comportamente ca sa scap de un fisier ar fi riscat cele 10 diagrame de acolo, pentru zero castig. Ia doar `spread` reparat. Reparatia schimba 4 documente, deci PROGRESS gresea cand spunea ca nicio diagrama comisa nu sufera de bug: 08 si 10 se misca cu 0,2 px, dar 07 si 09 aveau etichete la 6 px de linia lor. Verificat cu ochii pe 3 diagrame randate - etichetele stau acum pe linia lor, cu liniuta de legatura unde a trebuit mutata. audit_diagrams: 0 probleme. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
This commit is contained in:
@@ -23,95 +23,7 @@ STYLE = dict(gap=15, body_w=9, left=44, width=620)
|
||||
svgs = {}
|
||||
|
||||
|
||||
@dataclass
|
||||
class Seg:
|
||||
"""nivel valabil doar pe barele i0..i1"""
|
||||
i0: int
|
||||
i1: int
|
||||
price: float
|
||||
text: str
|
||||
color: str = ORANGE
|
||||
label_at: str = "out"
|
||||
dy: float = -5.0
|
||||
dash: str = ""
|
||||
|
||||
|
||||
def spread(items, gap=14):
|
||||
"""[(y, ...)] -> aceleași, cu y-urile împinse ca două etichete să nu se atingă"""
|
||||
items = sorted(items, key=lambda t: t[0])
|
||||
out = []
|
||||
for it in items:
|
||||
y = it[0] if not out else max(it[0], out[-1][0] + gap)
|
||||
out.append((y,) + tuple(it[1:]))
|
||||
return out
|
||||
|
||||
|
||||
@dataclass
|
||||
class PChart(Chart):
|
||||
"""copiat din gen/az_pivoti.py (vezi acolo explicațiile)"""
|
||||
segs: list = field(default_factory=list)
|
||||
seps: list = field(default_factory=list)
|
||||
pad_px: float = 24.0
|
||||
lm: int = 104
|
||||
pad_bot_px: float = 0.0
|
||||
|
||||
def render(self) -> str:
|
||||
n = len(self.candles)
|
||||
self.left = self.lm if any(s.label_at == "lm" for s in self.segs) else self.left
|
||||
segs = list(self.segs) + [Seg(0, n - 1, lv.price, lv.text, lv.color, "out", dash="4 3")
|
||||
for lv in self.levels]
|
||||
saved_lv, saved_ma = list(self.levels), list(self.mas)
|
||||
longest = max([len(s.text) for s in segs if s.label_at == "out"] + [len(m.text) for m in saved_ma] + [0])
|
||||
self.width = max(self.width, int(self._cx(n - 1) + self.gap / 2 + 6 + longest * 6.2 + 8))
|
||||
top_price = max([c.h for c in self.candles] + [s.price for s in segs])
|
||||
self.levels = [Level(s.price, "", "none") for s in segs]
|
||||
self.levels.append(Level(top_price + self.pad_px / self.scale, "", "none"))
|
||||
if self.pad_bot_px:
|
||||
low_price = min([c.l for c in self.candles] + [s.price for s in segs])
|
||||
self.levels.append(Level(low_price - self.pad_bot_px / self.scale, "", "none"))
|
||||
self.mas = [MA(m.period, m.color, m.dash) for m in saved_ma]
|
||||
svg = self.render_base()
|
||||
self.levels, self.mas = saved_lv, saved_ma
|
||||
parts = svg.split("\n ")
|
||||
extra = []
|
||||
for k in self.seps:
|
||||
x = self._cx(k) - self.gap / 2
|
||||
extra.append(f'<line x1="{x:.1f}" y1="{self.top - 4:.1f}" x2="{x:.1f}" '
|
||||
f'y2="{self._body_bottom:.1f}" stroke="#bbb" stroke-dasharray="2 3"/>')
|
||||
closes = [c.c for c in self.candles]
|
||||
xr = self._cx(n - 1) + self.gap / 2 + 6
|
||||
out_lab = [(self._y(s.price) + 4, s) for s in segs if s.label_at == "out"]
|
||||
out_lab += [(self._y(sum(closes[-m.period:]) / m.period) + 4, Seg(0, 0, 0, m.text, m.color))
|
||||
for m in saved_ma if m.text]
|
||||
placed = {id(s): y for y, s in spread(out_lab)}
|
||||
placed.update({id(s): y for y, s in spread([(self._y(s.price) + 4, s) for s in segs if s.label_at == "lm"])})
|
||||
for s in segs:
|
||||
x0, x1, y = self._cx(s.i0) - self.gap / 2, self._cx(s.i1) + self.gap / 2, self._y(s.price)
|
||||
dash = f' stroke-dasharray="{s.dash}"' if s.dash else ""
|
||||
extra.append(f'<line x1="{x0:.1f}" y1="{y:.1f}" x2="{x1:.1f}" y2="{y:.1f}" '
|
||||
f'stroke="{s.color}" stroke-width="{1.5 if s.dash else 2}"{dash}/>')
|
||||
if s.label_at == "out":
|
||||
extra.append(f'<text x="{xr:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
elif s.label_at == "lm":
|
||||
extra.append(f'<text x="{x0 - 6:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}" '
|
||||
f'text-anchor="end">{s.text}</text>')
|
||||
elif s.label_at == "left":
|
||||
extra.append(f'<text x="{x0 + 3:.1f}" y="{y + s.dy:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
else:
|
||||
extra.append(f'<text x="{x1 - 3:.1f}" y="{y + s.dy:.1f}" fill="{s.color}" '
|
||||
f'text-anchor="end">{s.text}</text>')
|
||||
for y, s in out_lab:
|
||||
if s.i1 == 0 and s.price == 0:
|
||||
extra.append(f'<text x="{xr:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
k = 2 if self.title else 1
|
||||
return "\n ".join(parts[:k] + extra + parts[k:])
|
||||
|
||||
def render_base(self):
|
||||
svg = Chart.render(self)
|
||||
svg = re.sub(r'\n <line [^>]*stroke="none"[^>]*/>\n <text [^>]*fill="none"[^>]*></text>', "", svg)
|
||||
prices = [p for c in self.candles for p in (c.o, c.h, c.l, c.c)] + [lv.price for lv in self.levels]
|
||||
self._body_bottom = self.top + (max(prices) - min(prices)) * self.scale
|
||||
return svg
|
||||
from pchart import PChart, Seg, spread # noqa: E402
|
||||
|
||||
|
||||
def px_ratio(ch, a, b, c):
|
||||
|
||||
@@ -29,97 +29,9 @@ FACTS = {}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- layout (din az_pivoti.py)
|
||||
@dataclass
|
||||
class Seg:
|
||||
"""nivel valabil doar pe barele i0..i1"""
|
||||
i0: int
|
||||
i1: int
|
||||
price: float
|
||||
text: str
|
||||
color: str = ORANGE
|
||||
label_at: str = "out"
|
||||
dy: float = -5.0
|
||||
dash: str = ""
|
||||
from pchart import PChart, Seg, spread # noqa: E402
|
||||
|
||||
|
||||
def spread(items, gap=14):
|
||||
"""[(y, ...)] -> aceleași, cu y-urile împinse ca două etichete să nu se atingă"""
|
||||
items = sorted(items, key=lambda t: t[0])
|
||||
out = []
|
||||
for it in items:
|
||||
y = it[0] if not out else max(it[0], out[-1][0] + gap)
|
||||
out.append((y,) + tuple(it[1:]))
|
||||
return out
|
||||
|
||||
|
||||
@dataclass
|
||||
class PChart(Chart):
|
||||
segs: list = field(default_factory=list)
|
||||
seps: list = field(default_factory=list)
|
||||
pad_px: float = 24.0
|
||||
lm: int = 104
|
||||
pad_bot_px: float = 0.0
|
||||
|
||||
def render(self) -> str:
|
||||
n = len(self.candles)
|
||||
self.left = self.lm if any(s.label_at == "lm" for s in self.segs) else self.left
|
||||
segs = list(self.segs) + [Seg(0, n - 1, lv.price, lv.text, lv.color, "out", dash="4 3")
|
||||
for lv in self.levels]
|
||||
saved_lv, saved_ma = list(self.levels), list(self.mas)
|
||||
longest = max([len(s.text) for s in segs if s.label_at == "out"] + [len(m.text) for m in saved_ma] + [0])
|
||||
self.width = max(self.width, int(self._cx(n - 1) + self.gap / 2 + 6 + longest * 6.2 + 8))
|
||||
top_price = max([c.h for c in self.candles] + [s.price for s in segs])
|
||||
self.levels = [Level(s.price, "", "none") for s in segs]
|
||||
self.levels.append(Level(top_price + self.pad_px / self.scale, "", "none"))
|
||||
if self.pad_bot_px:
|
||||
low_price = min([c.l for c in self.candles] + [s.price for s in segs])
|
||||
self.levels.append(Level(low_price - self.pad_bot_px / self.scale, "", "none"))
|
||||
self.mas = [MA(m.period, m.color, m.dash) for m in saved_ma]
|
||||
svg = self.render_base()
|
||||
self.levels, self.mas = saved_lv, saved_ma
|
||||
parts = svg.split("\n ")
|
||||
extra = []
|
||||
for k in self.seps:
|
||||
x = self._cx(k) - self.gap / 2
|
||||
extra.append(f'<line x1="{x:.1f}" y1="{self.top - 4:.1f}" x2="{x:.1f}" '
|
||||
f'y2="{self._body_bottom:.1f}" stroke="#bbb" stroke-dasharray="2 3"/>')
|
||||
closes = [c.c for c in self.candles]
|
||||
xr = self._cx(n - 1) + self.gap / 2 + 6
|
||||
out_lab = [(self._y(s.price) + 4, s) for s in segs if s.label_at == "out"]
|
||||
out_lab += [(self._y(sum(closes[-m.period:]) / m.period) + 4, Seg(0, 0, 0, m.text, m.color))
|
||||
for m in saved_ma if m.text]
|
||||
placed = {id(s): y for y, s in spread(out_lab)}
|
||||
placed.update({id(s): y for y, s in spread([(self._y(s.price) + 4, s) for s in segs if s.label_at == "lm"])})
|
||||
for s in segs:
|
||||
x0, x1, y = self._cx(s.i0) - self.gap / 2, self._cx(s.i1) + self.gap / 2, self._y(s.price)
|
||||
dash = f' stroke-dasharray="{s.dash}"' if s.dash else ""
|
||||
extra.append(f'<line x1="{x0:.1f}" y1="{y:.1f}" x2="{x1:.1f}" y2="{y:.1f}" '
|
||||
f'stroke="{s.color}" stroke-width="{1.5 if s.dash else 2}"{dash}/>')
|
||||
if s.label_at == "out":
|
||||
extra.append(f'<text x="{xr:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
elif s.label_at == "lm":
|
||||
extra.append(f'<text x="{x0 - 6:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}" '
|
||||
f'text-anchor="end">{s.text}</text>')
|
||||
elif s.label_at == "left":
|
||||
extra.append(f'<text x="{x0 + 3:.1f}" y="{y + s.dy:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
else:
|
||||
extra.append(f'<text x="{x1 - 3:.1f}" y="{y + s.dy:.1f}" fill="{s.color}" '
|
||||
f'text-anchor="end">{s.text}</text>')
|
||||
for y, s in out_lab:
|
||||
if s.i1 == 0 and s.price == 0:
|
||||
extra.append(f'<text x="{xr:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
k = 2 if self.title else 1
|
||||
return "\n ".join(parts[:k] + extra + parts[k:])
|
||||
|
||||
def render_base(self):
|
||||
svg = Chart.render(self)
|
||||
svg = re.sub(r'\n <line [^>]*stroke="none"[^>]*/>\n <text [^>]*fill="none"[^>]*></text>', "", svg)
|
||||
prices = [p for c in self.candles for p in (c.o, c.h, c.l, c.c)] + [lv.price for lv in self.levels]
|
||||
self._body_bottom = self.top + (max(prices) - min(prices)) * self.scale
|
||||
return svg
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- utilitare
|
||||
def series(closes, start, wicks=None, opens=None, vols=None):
|
||||
"""ca from_closes, dar cu open explicit pe barele de gap (opens={i: open})"""
|
||||
wicks, opens = wicks or {}, opens or {}
|
||||
|
||||
@@ -26,27 +26,11 @@ RISC = 25.0
|
||||
svgs = {}
|
||||
|
||||
|
||||
@dataclass
|
||||
class Seg:
|
||||
"""nivel valabil doar pe barele i0..i1"""
|
||||
i0: int
|
||||
i1: int
|
||||
price: float
|
||||
text: str
|
||||
color: str = ORANGE
|
||||
label_at: str = "out" # "out" marginea dreaptă | "lm" marginea stângă | "left"/"right" pe linie
|
||||
dy: float = -5.0
|
||||
dash: str = ""
|
||||
|
||||
|
||||
def spread(items, gap=14):
|
||||
"""[(y, ...)] -> aceleași, cu y-urile împinse ca două etichete să nu se atingă"""
|
||||
items = sorted(items, key=lambda t: t[0])
|
||||
out = []
|
||||
for it in items:
|
||||
y = it[0] if not out else max(it[0], out[-1][0] + gap)
|
||||
out.append((y,) + tuple(it[1:]))
|
||||
return out
|
||||
# `Seg` si `spread` vin din pchart.py. `PChart` NU: varianta de aici calculeaza
|
||||
# mediile dintr-un istoric de close-uri dinainte de bara 0 (`hist`), ca SMA-20 sa
|
||||
# fie deja incalzita la prima bara desenata, si si le deseneaza singura. Clasa
|
||||
# comuna nu are nevoie de asta, iar unirea lor ar risca cele 10 diagrame de aici.
|
||||
from pchart import Seg, spread # noqa: E402
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
102
gen/az_pivoti.py
102
gen/az_pivoti.py
@@ -24,107 +24,7 @@ STYLE = dict(gap=15, body_w=9, left=44, width=830)
|
||||
svgs = {}
|
||||
|
||||
|
||||
@dataclass
|
||||
class Seg:
|
||||
"""nivel valabil doar pe barele i0..i1 (o lună, un trimestru)"""
|
||||
i0: int
|
||||
i1: int
|
||||
price: float
|
||||
text: str
|
||||
color: str = ORANGE
|
||||
label_at: str = "out" # "out" marginea dreaptă | "lm" marginea stângă | "left"/"right" pe linie
|
||||
dy: float = -5.0 # pentru "left"/"right": eticheta deasupra liniei (negativ) sau dedesubt
|
||||
dash: str = ""
|
||||
|
||||
|
||||
def spread(items, gap=14):
|
||||
"""[(y, ...)] -> aceleași, cu y-urile împinse ca două etichete să nu se atingă"""
|
||||
# grupurile care se ating se centrează pe media pozițiilor naturale (nu doar împinse în jos),
|
||||
# altfel o etichetă care coincide cu linia de deasupra decalează toate etichetele de sub ea
|
||||
groups = [] # [start_y, [items]]
|
||||
for it in sorted(items, key=lambda t: t[0]):
|
||||
groups.append([it[0], [it]])
|
||||
while len(groups) > 1 and groups[-2][0] + gap * len(groups[-2][1]) > groups[-1][0]:
|
||||
last = groups.pop()
|
||||
its = groups[-1][1] + last[1]
|
||||
groups[-1] = [sum(t[0] - gap * k for k, t in enumerate(its)) / len(its), its]
|
||||
return [(g[0] + gap * k,) + tuple(t[1:]) for g in groups for k, t in enumerate(g[1])]
|
||||
|
||||
|
||||
@dataclass
|
||||
class PChart(Chart):
|
||||
"""Chart cu niveluri pe perioade. Nivelurile (`levels`) devin segmente pe toată seria;
|
||||
etichetele stau în margini (dreapta / stânga), niciodată peste candele."""
|
||||
segs: list = field(default_factory=list)
|
||||
seps: list = field(default_factory=list) # indecși unde începe o perioadă nouă
|
||||
pad_px: float = 24.0 # spațiu între cel mai sus preț și titlu
|
||||
lm: int = 104 # marginea stângă pentru etichetele "lm"
|
||||
pad_bot_px: float = 0.0 # spațiu sub cel mai jos preț, pentru etichetele de sub candele
|
||||
|
||||
def render(self) -> str:
|
||||
n = len(self.candles)
|
||||
self.left = self.lm if any(s.label_at == "lm" for s in self.segs) else self.left
|
||||
segs = list(self.segs) + [Seg(0, n - 1, lv.price, lv.text, lv.color, "out", dash="4 3")
|
||||
for lv in self.levels]
|
||||
saved_lv, saved_ma = list(self.levels), list(self.mas)
|
||||
# lățimea: cât să încapă cea mai lungă etichetă din marginea dreaptă
|
||||
longest = max([len(s.text) for s in segs if s.label_at == "out"] + [len(m.text) for m in saved_ma] + [0])
|
||||
self.width = max(self.width, int(self._cx(n - 1) + self.gap / 2 + 6 + longest * 6.2 + 8))
|
||||
top_price = max([c.h for c in self.candles] + [s.price for s in segs])
|
||||
# prețurile segmentelor intră în scară ca niveluri invizibile
|
||||
self.levels = [Level(s.price, "", "none") for s in segs]
|
||||
self.levels.append(Level(top_price + self.pad_px / self.scale, "", "none"))
|
||||
if self.pad_bot_px:
|
||||
low_price = min([c.l for c in self.candles] + [s.price for s in segs])
|
||||
self.levels.append(Level(low_price - self.pad_bot_px / self.scale, "", "none"))
|
||||
self.mas = [MA(m.period, m.color, m.dash) for m in saved_ma] # eticheta MA o punem noi, în margine
|
||||
svg = self.render_base()
|
||||
self.levels, self.mas = saved_lv, saved_ma
|
||||
parts = svg.split("\n ")
|
||||
extra = []
|
||||
for k in self.seps:
|
||||
x = self._cx(k) - self.gap / 2
|
||||
extra.append(f'<line x1="{x:.1f}" y1="{self.top - 4:.1f}" x2="{x:.1f}" '
|
||||
f'y2="{self._body_bottom:.1f}" stroke="#bbb" stroke-dasharray="2 3"/>')
|
||||
closes = [c.c for c in self.candles]
|
||||
xr = self._cx(n - 1) + self.gap / 2 + 6
|
||||
out_lab = [(self._y(s.price) + 4, s) for s in segs if s.label_at == "out"]
|
||||
out_lab += [(self._y(sum(closes[-m.period:]) / m.period) + 4, Seg(0, 0, 0, m.text, m.color))
|
||||
for m in saved_ma if m.text]
|
||||
placed = {id(s): y for y, s in spread(out_lab)}
|
||||
placed.update({id(s): y for y, s in spread([(self._y(s.price) + 4, s) for s in segs if s.label_at == "lm"])})
|
||||
for y, s in out_lab: # etichetă mutată de pe linia ei: legătură scurtă până la ea
|
||||
if abs(placed[id(s)] - y) > 3:
|
||||
extra.append(f'<line x1="{xr - 6:.1f}" y1="{y - 4:.1f}" x2="{xr - 1:.1f}" '
|
||||
f'y2="{placed[id(s)] - 4:.1f}" stroke="{s.color}" stroke-width="1"/>')
|
||||
for s in segs:
|
||||
x0, x1, y = self._cx(s.i0) - self.gap / 2, self._cx(s.i1) + self.gap / 2, self._y(s.price)
|
||||
dash = f' stroke-dasharray="{s.dash}"' if s.dash else ""
|
||||
extra.append(f'<line x1="{x0:.1f}" y1="{y:.1f}" x2="{x1:.1f}" y2="{y:.1f}" '
|
||||
f'stroke="{s.color}" stroke-width="{1.5 if s.dash else 2}"{dash}/>')
|
||||
if s.label_at == "out":
|
||||
extra.append(f'<text x="{xr:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
elif s.label_at == "lm":
|
||||
extra.append(f'<text x="{x0 - 6:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}" '
|
||||
f'text-anchor="end">{s.text}</text>')
|
||||
elif s.label_at == "left":
|
||||
extra.append(f'<text x="{x0 + 3:.1f}" y="{y + s.dy:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
else:
|
||||
extra.append(f'<text x="{x1 - 3:.1f}" y="{y + s.dy:.1f}" fill="{s.color}" '
|
||||
f'text-anchor="end">{s.text}</text>')
|
||||
for y, s in out_lab:
|
||||
if s.i1 == 0 and s.price == 0: # eticheta de MA
|
||||
extra.append(f'<text x="{xr:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
k = 2 if self.title else 1
|
||||
return "\n ".join(parts[:k] + extra + parts[k:])
|
||||
|
||||
def render_base(self):
|
||||
svg = Chart.render(self)
|
||||
# nivelurile invizibile lasă linii/etichete goale: le scoatem
|
||||
svg = re.sub(r'\n <line [^>]*stroke="none"[^>]*/>\n <text [^>]*fill="none"[^>]*></text>', "", svg)
|
||||
prices = [p for c in self.candles for p in (c.o, c.h, c.l, c.c)] + [lv.price for lv in self.levels]
|
||||
self._body_bottom = self.top + (max(prices) - min(prices)) * self.scale
|
||||
return svg
|
||||
from pchart import PChart, Seg, spread # noqa: E402
|
||||
|
||||
|
||||
def pivots(bars):
|
||||
|
||||
@@ -24,88 +24,7 @@ svgs = {}
|
||||
|
||||
|
||||
# ------------------------------------------------ PChart, copiat din gen/az_pivoti.py
|
||||
@dataclass
|
||||
class Seg:
|
||||
"""nivel valabil doar pe barele i0..i1 (o lună)"""
|
||||
i0: int
|
||||
i1: int
|
||||
price: float
|
||||
text: str
|
||||
color: str = ORANGE
|
||||
label_at: str = "out"
|
||||
dy: float = -5.0
|
||||
dash: str = ""
|
||||
|
||||
|
||||
def spread(items, gap=14):
|
||||
items = sorted(items, key=lambda t: t[0])
|
||||
out = []
|
||||
for it in items:
|
||||
y = it[0] if not out else max(it[0], out[-1][0] + gap)
|
||||
out.append((y,) + tuple(it[1:]))
|
||||
return out
|
||||
|
||||
|
||||
@dataclass
|
||||
class PChart(Chart):
|
||||
segs: list = field(default_factory=list)
|
||||
seps: list = field(default_factory=list)
|
||||
pad_px: float = 24.0
|
||||
lm: int = 104
|
||||
pad_bot_px: float = 0.0
|
||||
|
||||
def render(self) -> str:
|
||||
n = len(self.candles)
|
||||
self.left = self.lm if any(s.label_at == "lm" for s in self.segs) else self.left
|
||||
segs = list(self.segs) + [Seg(0, n - 1, lv.price, lv.text, lv.color, "out", dash="4 3")
|
||||
for lv in self.levels]
|
||||
saved_lv, saved_ma = list(self.levels), list(self.mas)
|
||||
longest = max([len(s.text) for s in segs if s.label_at == "out"] + [len(m.text) for m in saved_ma] + [0])
|
||||
self.width = max(self.width, int(self._cx(n - 1) + self.gap / 2 + 6 + longest * 6.2 + 8))
|
||||
top_price = max([c.h for c in self.candles] + [s.price for s in segs])
|
||||
self.levels = [Level(s.price, "", "none") for s in segs]
|
||||
self.levels.append(Level(top_price + self.pad_px / self.scale, "", "none"))
|
||||
if self.pad_bot_px:
|
||||
low_price = min([c.l for c in self.candles] + [s.price for s in segs])
|
||||
self.levels.append(Level(low_price - self.pad_bot_px / self.scale, "", "none"))
|
||||
self.mas = [MA(m.period, m.color, m.dash) for m in saved_ma]
|
||||
svg = self.render_base()
|
||||
self.levels, self.mas = saved_lv, saved_ma
|
||||
parts = svg.split("\n ")
|
||||
extra = []
|
||||
for k in self.seps:
|
||||
x = self._cx(k) - self.gap / 2
|
||||
extra.append(f'<line x1="{x:.1f}" y1="{self.top - 4:.1f}" x2="{x:.1f}" '
|
||||
f'y2="{self._body_bottom:.1f}" stroke="#bbb" stroke-dasharray="2 3"/>')
|
||||
closes = [c.c for c in self.candles]
|
||||
xr = self._cx(n - 1) + self.gap / 2 + 6
|
||||
out_lab = [(self._y(s.price) + 4, s) for s in segs if s.label_at == "out"]
|
||||
out_lab += [(self._y(sum(closes[-m.period:]) / m.period) + 4, Seg(0, 0, 0, m.text, m.color))
|
||||
for m in saved_ma if m.text]
|
||||
placed = {id(s): y for y, s in spread(out_lab)}
|
||||
placed.update({id(s): y for y, s in spread([(self._y(s.price) + 4, s) for s in segs if s.label_at == "lm"])})
|
||||
for s in segs:
|
||||
x0, x1, y = self._cx(s.i0) - self.gap / 2, self._cx(s.i1) + self.gap / 2, self._y(s.price)
|
||||
dash = f' stroke-dasharray="{s.dash}"' if s.dash else ""
|
||||
extra.append(f'<line x1="{x0:.1f}" y1="{y:.1f}" x2="{x1:.1f}" y2="{y:.1f}" '
|
||||
f'stroke="{s.color}" stroke-width="{1.5 if s.dash else 2}"{dash}/>')
|
||||
if s.label_at == "out":
|
||||
extra.append(f'<text x="{xr:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
elif s.label_at == "lm":
|
||||
extra.append(f'<text x="{x0 - 6:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}" '
|
||||
f'text-anchor="end">{s.text}</text>')
|
||||
for y, s in out_lab:
|
||||
if s.i1 == 0 and s.price == 0:
|
||||
extra.append(f'<text x="{xr:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
k = 2 if self.title else 1
|
||||
return "\n ".join(parts[:k] + extra + parts[k:])
|
||||
|
||||
def render_base(self):
|
||||
svg = Chart.render(self)
|
||||
svg = re.sub(r'\n <line [^>]*stroke="none"[^>]*/>\n <text [^>]*fill="none"[^>]*></text>', "", svg)
|
||||
prices = [p for c in self.candles for p in (c.o, c.h, c.l, c.c)] + [lv.price for lv in self.levels]
|
||||
self._body_bottom = self.top + (max(prices) - min(prices)) * self.scale
|
||||
return svg
|
||||
from pchart import PChart, Seg, spread # noqa: E402
|
||||
|
||||
|
||||
def pivots(bars):
|
||||
|
||||
121
gen/pchart.py
Normal file
121
gen/pchart.py
Normal file
@@ -0,0 +1,121 @@
|
||||
"""Nucleul comun al generatoarelor de Analiza Zilnica: `PChart` si `spread`.
|
||||
|
||||
Era copiat in cinci generatoare, iar copiile divergisera: reparatia din
|
||||
`spread()` (grupurile care se ating se centreaza pe media pozitiilor
|
||||
naturale, nu doar se impig in jos - altfel o eticheta care cade fix pe
|
||||
linia de deasupra decaleaza toate etichetele de sub ea) traia doar in
|
||||
`az_pivoti.py`. Aici e versiunea buna, singura.
|
||||
|
||||
Un generator nou importa de aici:
|
||||
|
||||
from pchart import PChart, Seg, spread
|
||||
"""
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from svg_candles import Chart, Level, Mark, MA
|
||||
|
||||
GRAY, RED, GREEN, BLUE, ORANGE, PURPLE = "#777", "#c00", "#188a3e", "#1a5fb4", "#b06000", "#6a3d9a"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Seg:
|
||||
"""nivel valabil doar pe barele i0..i1 (o lună, un trimestru)"""
|
||||
i0: int
|
||||
i1: int
|
||||
price: float
|
||||
text: str
|
||||
color: str = ORANGE
|
||||
label_at: str = "out" # "out" marginea dreaptă | "lm" marginea stângă | "left"/"right" pe linie
|
||||
dy: float = -5.0 # pentru "left"/"right": eticheta deasupra liniei (negativ) sau dedesubt
|
||||
dash: str = ""
|
||||
|
||||
|
||||
def spread(items, gap=14):
|
||||
"""[(y, ...)] -> aceleași, cu y-urile împinse ca două etichete să nu se atingă"""
|
||||
# grupurile care se ating se centrează pe media pozițiilor naturale (nu doar împinse în jos),
|
||||
# altfel o etichetă care coincide cu linia de deasupra decalează toate etichetele de sub ea
|
||||
groups = [] # [start_y, [items]]
|
||||
for it in sorted(items, key=lambda t: t[0]):
|
||||
groups.append([it[0], [it]])
|
||||
while len(groups) > 1 and groups[-2][0] + gap * len(groups[-2][1]) > groups[-1][0]:
|
||||
last = groups.pop()
|
||||
its = groups[-1][1] + last[1]
|
||||
groups[-1] = [sum(t[0] - gap * k for k, t in enumerate(its)) / len(its), its]
|
||||
return [(g[0] + gap * k,) + tuple(t[1:]) for g in groups for k, t in enumerate(g[1])]
|
||||
|
||||
|
||||
@dataclass
|
||||
class PChart(Chart):
|
||||
"""Chart cu niveluri pe perioade. Nivelurile (`levels`) devin segmente pe toată seria;
|
||||
etichetele stau în margini (dreapta / stânga), niciodată peste candele."""
|
||||
segs: list = field(default_factory=list)
|
||||
seps: list = field(default_factory=list) # indecși unde începe o perioadă nouă
|
||||
pad_px: float = 24.0 # spațiu între cel mai sus preț și titlu
|
||||
lm: int = 104 # marginea stângă pentru etichetele "lm"
|
||||
pad_bot_px: float = 0.0 # spațiu sub cel mai jos preț, pentru etichetele de sub candele
|
||||
|
||||
def render(self) -> str:
|
||||
n = len(self.candles)
|
||||
self.left = self.lm if any(s.label_at == "lm" for s in self.segs) else self.left
|
||||
segs = list(self.segs) + [Seg(0, n - 1, lv.price, lv.text, lv.color, "out", dash="4 3")
|
||||
for lv in self.levels]
|
||||
saved_lv, saved_ma = list(self.levels), list(self.mas)
|
||||
# lățimea: cât să încapă cea mai lungă etichetă din marginea dreaptă
|
||||
longest = max([len(s.text) for s in segs if s.label_at == "out"] + [len(m.text) for m in saved_ma] + [0])
|
||||
self.width = max(self.width, int(self._cx(n - 1) + self.gap / 2 + 6 + longest * 6.2 + 8))
|
||||
top_price = max([c.h for c in self.candles] + [s.price for s in segs])
|
||||
# prețurile segmentelor intră în scară ca niveluri invizibile
|
||||
self.levels = [Level(s.price, "", "none") for s in segs]
|
||||
self.levels.append(Level(top_price + self.pad_px / self.scale, "", "none"))
|
||||
if self.pad_bot_px:
|
||||
low_price = min([c.l for c in self.candles] + [s.price for s in segs])
|
||||
self.levels.append(Level(low_price - self.pad_bot_px / self.scale, "", "none"))
|
||||
self.mas = [MA(m.period, m.color, m.dash) for m in saved_ma] # eticheta MA o punem noi, în margine
|
||||
svg = self.render_base()
|
||||
self.levels, self.mas = saved_lv, saved_ma
|
||||
parts = svg.split("\n ")
|
||||
extra = []
|
||||
for k in self.seps:
|
||||
x = self._cx(k) - self.gap / 2
|
||||
extra.append(f'<line x1="{x:.1f}" y1="{self.top - 4:.1f}" x2="{x:.1f}" '
|
||||
f'y2="{self._body_bottom:.1f}" stroke="#bbb" stroke-dasharray="2 3"/>')
|
||||
closes = [c.c for c in self.candles]
|
||||
xr = self._cx(n - 1) + self.gap / 2 + 6
|
||||
out_lab = [(self._y(s.price) + 4, s) for s in segs if s.label_at == "out"]
|
||||
out_lab += [(self._y(sum(closes[-m.period:]) / m.period) + 4, Seg(0, 0, 0, m.text, m.color))
|
||||
for m in saved_ma if m.text]
|
||||
placed = {id(s): y for y, s in spread(out_lab)}
|
||||
placed.update({id(s): y for y, s in spread([(self._y(s.price) + 4, s) for s in segs if s.label_at == "lm"])})
|
||||
for y, s in out_lab: # etichetă mutată de pe linia ei: legătură scurtă până la ea
|
||||
if abs(placed[id(s)] - y) > 3:
|
||||
extra.append(f'<line x1="{xr - 6:.1f}" y1="{y - 4:.1f}" x2="{xr - 1:.1f}" '
|
||||
f'y2="{placed[id(s)] - 4:.1f}" stroke="{s.color}" stroke-width="1"/>')
|
||||
for s in segs:
|
||||
x0, x1, y = self._cx(s.i0) - self.gap / 2, self._cx(s.i1) + self.gap / 2, self._y(s.price)
|
||||
dash = f' stroke-dasharray="{s.dash}"' if s.dash else ""
|
||||
extra.append(f'<line x1="{x0:.1f}" y1="{y:.1f}" x2="{x1:.1f}" y2="{y:.1f}" '
|
||||
f'stroke="{s.color}" stroke-width="{1.5 if s.dash else 2}"{dash}/>')
|
||||
if s.label_at == "out":
|
||||
extra.append(f'<text x="{xr:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
elif s.label_at == "lm":
|
||||
extra.append(f'<text x="{x0 - 6:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}" '
|
||||
f'text-anchor="end">{s.text}</text>')
|
||||
elif s.label_at == "left":
|
||||
extra.append(f'<text x="{x0 + 3:.1f}" y="{y + s.dy:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
else:
|
||||
extra.append(f'<text x="{x1 - 3:.1f}" y="{y + s.dy:.1f}" fill="{s.color}" '
|
||||
f'text-anchor="end">{s.text}</text>')
|
||||
for y, s in out_lab:
|
||||
if s.i1 == 0 and s.price == 0: # eticheta de MA
|
||||
extra.append(f'<text x="{xr:.1f}" y="{placed[id(s)]:.1f}" fill="{s.color}">{s.text}</text>')
|
||||
k = 2 if self.title else 1
|
||||
return "\n ".join(parts[:k] + extra + parts[k:])
|
||||
|
||||
def render_base(self):
|
||||
svg = Chart.render(self)
|
||||
# nivelurile invizibile lasă linii/etichete goale: le scoatem
|
||||
svg = re.sub(r'\n <line [^>]*stroke="none"[^>]*/>\n <text [^>]*fill="none"[^>]*></text>', "", svg)
|
||||
prices = [p for c in self.candles for p in (c.o, c.h, c.l, c.c)] + [lv.price for lv in self.levels]
|
||||
self._body_bottom = self.top + (max(prices) - min(prices)) * self.scale
|
||||
return svg
|
||||
@@ -366,9 +366,9 @@ de la RSP, care este S&P-ul equal weight" (17.08)</p>
|
||||
<line x1="36.5" y1="80.0" x2="636.5" y2="80.0" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="642.5" y="84.0" fill="#c00">SL 57.50</text>
|
||||
<line x1="36.5" y1="106.4" x2="636.5" y2="106.4" stroke="#777" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="642.5" y="110.4" fill="#777">vârf 1 56.30</text>
|
||||
<text x="642.5" y="107.8" fill="#777">vârf 1 56.30</text>
|
||||
<line x1="36.5" y1="115.2" x2="636.5" y2="115.2" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="642.5" y="124.4" fill="#188a3e">intrare short 55.90</text>
|
||||
<text x="642.5" y="121.8" fill="#188a3e">intrare short 55.90</text>
|
||||
<line x1="36.5" y1="185.6" x2="636.5" y2="185.6" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="642.5" y="189.6" fill="#1a5fb4">TP 52.70 = 2R</text>
|
||||
<line x1="44.0" y1="238.4" x2="44.0" y2="256.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
@@ -915,17 +915,19 @@ spike-ul e o bară de peste 2x media.</p>
|
||||
<!--SVG:atr_spike-->
|
||||
<p><svg viewBox="0 0 882 447" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily, indicele</text>
|
||||
<line x1="651.5" y1="216.8" x2="656.5" y2="210.7" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="651.5" y1="218.6" x2="656.5" y2="224.7" stroke="#c00" stroke-width="1"/>
|
||||
<line x1="36.5" y1="105.2" x2="651.5" y2="105.2" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="657.5" y="109.2" fill="#1a5fb4">TP2 60.80 = 2R</text>
|
||||
<line x1="36.5" y1="148.4" x2="651.5" y2="148.4" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="657.5" y="152.8" fill="#1a5fb4">TP1 58.40 = 1/2 până la vârf (0.9R)</text>
|
||||
<text x="657.5" y="152.6" fill="#1a5fb4">TP1 58.40 = 1/2 până la vârf (0.9R)</text>
|
||||
<line x1="36.5" y1="180.8" x2="651.5" y2="180.8" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="657.5" y="184.8" fill="#188a3e">intrare 56.60</text>
|
||||
<line x1="36.5" y1="216.8" x2="651.5" y2="216.8" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="657.5" y="220.8" fill="#b06000">locul crimei 54.60</text>
|
||||
<text x="657.5" y="214.7" fill="#b06000">locul crimei 54.60</text>
|
||||
<line x1="36.5" y1="218.6" x2="651.5" y2="218.6" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="657.5" y="234.8" fill="#c00">SL 54.50</text>
|
||||
<text x="657.5" y="138.8" fill="#777">SMA-20</text>
|
||||
<text x="657.5" y="228.7" fill="#c00">SL 54.50</text>
|
||||
<text x="657.5" y="138.6" fill="#777">SMA-20</text>
|
||||
<polyline points="329.0,231.3 344.0,223.0 359.0,215.5 374.0,207.4 389.0,198.1 404.0,188.7 419.0,180.5 434.0,171.8 449.0,165.0 464.0,159.6 479.0,156.3 494.0,154.2 509.0,151.7 524.0,149.2 539.0,147.1 554.0,145.1 569.0,143.1 584.0,141.2 599.0,139.5 614.0,137.8 629.0,136.3 644.0,134.8" fill="none" stroke="#777" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<line x1="44.0" y1="296.0" x2="44.0" y2="308.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="39.5" y="299.6" width="9" height="5.4" fill="#188a3e"/>
|
||||
@@ -1080,9 +1082,11 @@ oversold + locul crimei / gap închis / SMA 20</strong>.</p>
|
||||
<!--SVG:atr_nu-->
|
||||
<p><svg viewBox="0 0 702 423" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily, indicele</text>
|
||||
<line x1="576.5" y1="145.0" x2="581.5" y2="141.6" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="576.5" y1="152.3" x2="581.5" y2="155.6" stroke="#777" stroke-width="1"/>
|
||||
<line x1="36.5" y1="145.0" x2="576.5" y2="145.0" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="582.5" y="149.0" fill="#b06000">locul crimei 54.80</text>
|
||||
<text x="582.5" y="163.0" fill="#777">SMA-20</text>
|
||||
<text x="582.5" y="145.6" fill="#b06000">locul crimei 54.80</text>
|
||||
<text x="582.5" y="159.6" fill="#777">SMA-20</text>
|
||||
<polyline points="329.0,166.8 344.0,159.9 359.0,153.8 374.0,148.9 389.0,144.0 404.0,140.1 419.0,137.5 434.0,134.9 449.0,133.4 464.0,133.3 479.0,134.2 494.0,134.3 509.0,136.2 524.0,139.0 539.0,142.7 554.0,147.6 569.0,152.3" fill="none" stroke="#777" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<line x1="44.0" y1="262.0" x2="44.0" y2="285.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="39.5" y="269.8" width="9" height="7.8" fill="#188a3e"/>
|
||||
@@ -1656,16 +1660,18 @@ mare, atenție la tranzacții în jurul orei (04.09).</p>
|
||||
<!--SVG:cpi_da-->
|
||||
<p><svg viewBox="0 0 734 475" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily, indicele</text>
|
||||
<line x1="621.5" y1="207.6" x2="626.5" y2="202.4" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="621.5" y1="212.0" x2="626.5" y2="216.4" stroke="#c00" stroke-width="1"/>
|
||||
<line x1="36.5" y1="99.8" x2="621.5" y2="99.8" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="627.5" y="103.8" fill="#1a5fb4">TP 60.30 = 2R</text>
|
||||
<line x1="36.5" y1="174.6" x2="621.5" y2="174.6" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="627.5" y="178.6" fill="#188a3e">intrare 56.90</text>
|
||||
<line x1="36.5" y1="207.6" x2="621.5" y2="207.6" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="627.5" y="211.6" fill="#b06000">range high 55.40</text>
|
||||
<text x="627.5" y="206.4" fill="#b06000">range high 55.40</text>
|
||||
<line x1="36.5" y1="212.0" x2="621.5" y2="212.0" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="627.5" y="225.6" fill="#c00">SL 55.20</text>
|
||||
<text x="627.5" y="220.4" fill="#c00">SL 55.20</text>
|
||||
<line x1="36.5" y1="229.6" x2="621.5" y2="229.6" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="627.5" y="239.6" fill="#b06000">range low 54.40</text>
|
||||
<text x="627.5" y="234.4" fill="#b06000">range low 54.40</text>
|
||||
<line x1="44.0" y1="319.8" x2="44.0" y2="337.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="39.5" y="326.4" width="9" height="4.4" fill="#188a3e"/>
|
||||
<line x1="59.0" y1="308.8" x2="59.0" y2="333.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
|
||||
@@ -170,9 +170,9 @@ RSP nu face vârf nou, **compania medie nu urcă**.
|
||||
<line x1="36.5" y1="80.0" x2="636.5" y2="80.0" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="642.5" y="84.0" fill="#c00">SL 57.50</text>
|
||||
<line x1="36.5" y1="106.4" x2="636.5" y2="106.4" stroke="#777" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="642.5" y="110.4" fill="#777">vârf 1 56.30</text>
|
||||
<text x="642.5" y="107.8" fill="#777">vârf 1 56.30</text>
|
||||
<line x1="36.5" y1="115.2" x2="636.5" y2="115.2" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="642.5" y="124.4" fill="#188a3e">intrare short 55.90</text>
|
||||
<text x="642.5" y="121.8" fill="#188a3e">intrare short 55.90</text>
|
||||
<line x1="36.5" y1="185.6" x2="636.5" y2="185.6" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="642.5" y="189.6" fill="#1a5fb4">TP 52.70 = 2R</text>
|
||||
<line x1="44.0" y1="238.4" x2="44.0" y2="256.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
@@ -695,17 +695,19 @@ spike-ul e o bară de peste 2x media.
|
||||
<!--SVG:atr_spike-->
|
||||
<svg viewBox="0 0 882 447" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily, indicele</text>
|
||||
<line x1="651.5" y1="216.8" x2="656.5" y2="210.7" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="651.5" y1="218.6" x2="656.5" y2="224.7" stroke="#c00" stroke-width="1"/>
|
||||
<line x1="36.5" y1="105.2" x2="651.5" y2="105.2" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="657.5" y="109.2" fill="#1a5fb4">TP2 60.80 = 2R</text>
|
||||
<line x1="36.5" y1="148.4" x2="651.5" y2="148.4" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="657.5" y="152.8" fill="#1a5fb4">TP1 58.40 = 1/2 până la vârf (0.9R)</text>
|
||||
<text x="657.5" y="152.6" fill="#1a5fb4">TP1 58.40 = 1/2 până la vârf (0.9R)</text>
|
||||
<line x1="36.5" y1="180.8" x2="651.5" y2="180.8" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="657.5" y="184.8" fill="#188a3e">intrare 56.60</text>
|
||||
<line x1="36.5" y1="216.8" x2="651.5" y2="216.8" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="657.5" y="220.8" fill="#b06000">locul crimei 54.60</text>
|
||||
<text x="657.5" y="214.7" fill="#b06000">locul crimei 54.60</text>
|
||||
<line x1="36.5" y1="218.6" x2="651.5" y2="218.6" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="657.5" y="234.8" fill="#c00">SL 54.50</text>
|
||||
<text x="657.5" y="138.8" fill="#777">SMA-20</text>
|
||||
<text x="657.5" y="228.7" fill="#c00">SL 54.50</text>
|
||||
<text x="657.5" y="138.6" fill="#777">SMA-20</text>
|
||||
<polyline points="329.0,231.3 344.0,223.0 359.0,215.5 374.0,207.4 389.0,198.1 404.0,188.7 419.0,180.5 434.0,171.8 449.0,165.0 464.0,159.6 479.0,156.3 494.0,154.2 509.0,151.7 524.0,149.2 539.0,147.1 554.0,145.1 569.0,143.1 584.0,141.2 599.0,139.5 614.0,137.8 629.0,136.3 644.0,134.8" fill="none" stroke="#777" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<line x1="44.0" y1="296.0" x2="44.0" y2="308.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="39.5" y="299.6" width="9" height="5.4" fill="#188a3e"/>
|
||||
@@ -861,9 +863,11 @@ oversold + locul crimei / gap închis / SMA 20**.
|
||||
<!--SVG:atr_nu-->
|
||||
<svg viewBox="0 0 702 423" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily, indicele</text>
|
||||
<line x1="576.5" y1="145.0" x2="581.5" y2="141.6" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="576.5" y1="152.3" x2="581.5" y2="155.6" stroke="#777" stroke-width="1"/>
|
||||
<line x1="36.5" y1="145.0" x2="576.5" y2="145.0" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="582.5" y="149.0" fill="#b06000">locul crimei 54.80</text>
|
||||
<text x="582.5" y="163.0" fill="#777">SMA-20</text>
|
||||
<text x="582.5" y="145.6" fill="#b06000">locul crimei 54.80</text>
|
||||
<text x="582.5" y="159.6" fill="#777">SMA-20</text>
|
||||
<polyline points="329.0,166.8 344.0,159.9 359.0,153.8 374.0,148.9 389.0,144.0 404.0,140.1 419.0,137.5 434.0,134.9 449.0,133.4 464.0,133.3 479.0,134.2 494.0,134.3 509.0,136.2 524.0,139.0 539.0,142.7 554.0,147.6 569.0,152.3" fill="none" stroke="#777" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<line x1="44.0" y1="262.0" x2="44.0" y2="285.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="39.5" y="269.8" width="9" height="7.8" fill="#188a3e"/>
|
||||
@@ -1305,16 +1309,18 @@ mare, atenție la tranzacții în jurul orei (04.09).
|
||||
<!--SVG:cpi_da-->
|
||||
<svg viewBox="0 0 734 475" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily, indicele</text>
|
||||
<line x1="621.5" y1="207.6" x2="626.5" y2="202.4" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="621.5" y1="212.0" x2="626.5" y2="216.4" stroke="#c00" stroke-width="1"/>
|
||||
<line x1="36.5" y1="99.8" x2="621.5" y2="99.8" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="627.5" y="103.8" fill="#1a5fb4">TP 60.30 = 2R</text>
|
||||
<line x1="36.5" y1="174.6" x2="621.5" y2="174.6" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="627.5" y="178.6" fill="#188a3e">intrare 56.90</text>
|
||||
<line x1="36.5" y1="207.6" x2="621.5" y2="207.6" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="627.5" y="211.6" fill="#b06000">range high 55.40</text>
|
||||
<text x="627.5" y="206.4" fill="#b06000">range high 55.40</text>
|
||||
<line x1="36.5" y1="212.0" x2="621.5" y2="212.0" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="627.5" y="225.6" fill="#c00">SL 55.20</text>
|
||||
<text x="627.5" y="220.4" fill="#c00">SL 55.20</text>
|
||||
<line x1="36.5" y1="229.6" x2="621.5" y2="229.6" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="627.5" y="239.6" fill="#b06000">range low 54.40</text>
|
||||
<text x="627.5" y="234.4" fill="#b06000">range low 54.40</text>
|
||||
<line x1="44.0" y1="319.8" x2="44.0" y2="337.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="39.5" y="326.4" width="9" height="4.4" fill="#188a3e"/>
|
||||
<line x1="59.0" y1="308.8" x2="59.0" y2="333.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
|
||||
@@ -1367,12 +1367,12 @@ liquiditatea de pe high-ul ăsta des și aș intra în bucăți."</p>
|
||||
<line x1="381.5" y1="212.6" x2="636.5" y2="212.6" stroke="#777" stroke-width="1.5" stroke-dasharray="2 3"/>
|
||||
<text x="642.5" y="216.6" fill="#777">vârful după HL 434 (aici NU cumperi tot)</text>
|
||||
<line x1="351.5" y1="267.0" x2="636.5" y2="267.0" stroke="#188a3e" stroke-width="2"/>
|
||||
<text x="642.5" y="271.0" fill="#188a3e">tranșele 1 și 3: câte 2 acț. la 418 / 419</text>
|
||||
<text x="642.5" y="270.8" fill="#188a3e">tranșele 1 și 3: câte 2 acț. la 418 / 419</text>
|
||||
<line x1="411.5" y1="246.6" x2="636.5" y2="246.6" stroke="#188a3e" stroke-width="2"/>
|
||||
<text x="642.5" y="250.6" fill="#188a3e">tranșa 2: 2 acț. la 424 (1/3)</text>
|
||||
<line x1="426.5" y1="263.6" x2="636.5" y2="263.6" stroke="#188a3e" stroke-width="2"/>
|
||||
<line x1="441.5" y1="280.6" x2="636.5" y2="280.6" stroke="#188a3e" stroke-width="2"/>
|
||||
<text x="642.5" y="285.0" fill="#188a3e">tranșa 4: 2 acț. la 414 (2/3)</text>
|
||||
<text x="642.5" y="284.8" fill="#188a3e">tranșa 4: 2 acț. la 414 (2/3)</text>
|
||||
<line x1="351.5" y1="331.6" x2="636.5" y2="331.6" stroke="#c00" stroke-width="2"/>
|
||||
<text x="642.5" y="335.6" fill="#c00">SL comun 399 (sub HL 404)</text>
|
||||
<line x1="44.0" y1="151.4" x2="44.0" y2="182.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
|
||||
@@ -1105,12 +1105,12 @@ poziția: **4 tranșe de câte 1/4**. După higher low prețul poate retesta 1/3
|
||||
<line x1="381.5" y1="212.6" x2="636.5" y2="212.6" stroke="#777" stroke-width="1.5" stroke-dasharray="2 3"/>
|
||||
<text x="642.5" y="216.6" fill="#777">vârful după HL 434 (aici NU cumperi tot)</text>
|
||||
<line x1="351.5" y1="267.0" x2="636.5" y2="267.0" stroke="#188a3e" stroke-width="2"/>
|
||||
<text x="642.5" y="271.0" fill="#188a3e">tranșele 1 și 3: câte 2 acț. la 418 / 419</text>
|
||||
<text x="642.5" y="270.8" fill="#188a3e">tranșele 1 și 3: câte 2 acț. la 418 / 419</text>
|
||||
<line x1="411.5" y1="246.6" x2="636.5" y2="246.6" stroke="#188a3e" stroke-width="2"/>
|
||||
<text x="642.5" y="250.6" fill="#188a3e">tranșa 2: 2 acț. la 424 (1/3)</text>
|
||||
<line x1="426.5" y1="263.6" x2="636.5" y2="263.6" stroke="#188a3e" stroke-width="2"/>
|
||||
<line x1="441.5" y1="280.6" x2="636.5" y2="280.6" stroke="#188a3e" stroke-width="2"/>
|
||||
<text x="642.5" y="285.0" fill="#188a3e">tranșa 4: 2 acț. la 414 (2/3)</text>
|
||||
<text x="642.5" y="284.8" fill="#188a3e">tranșa 4: 2 acț. la 414 (2/3)</text>
|
||||
<line x1="351.5" y1="331.6" x2="636.5" y2="331.6" stroke="#c00" stroke-width="2"/>
|
||||
<text x="642.5" y="335.6" fill="#c00">SL comun 399 (sub HL 404)</text>
|
||||
<line x1="44.0" y1="151.4" x2="44.0" y2="182.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
|
||||
@@ -399,16 +399,20 @@ ai un nivel concret pentru stop: sub zona apărată.</p>
|
||||
<!--SVG:gap_pullback_da-->
|
||||
<p><svg viewBox="0 0 761 484" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily</text>
|
||||
<line x1="666.5" y1="193.4" x2="671.5" y2="188.2" stroke="#188a3e" stroke-width="1"/>
|
||||
<line x1="666.5" y1="197.0" x2="671.5" y2="202.2" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="666.5" y1="236.6" x2="671.5" y2="233.2" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="666.5" y1="243.8" x2="671.5" y2="247.2" stroke="#c00" stroke-width="1"/>
|
||||
<line x1="36.5" y1="92.6" x2="666.5" y2="92.6" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="96.6" fill="#1a5fb4">TP 72.50 = 2R</text>
|
||||
<line x1="36.5" y1="193.4" x2="666.5" y2="193.4" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="197.4" fill="#188a3e">intrare 66.90</text>
|
||||
<text x="672.5" y="192.2" fill="#188a3e">intrare 66.90</text>
|
||||
<line x1="36.5" y1="197.0" x2="666.5" y2="197.0" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="211.4" fill="#b06000">sus gap 66.70</text>
|
||||
<text x="672.5" y="206.2" fill="#b06000">sus gap 66.70</text>
|
||||
<line x1="36.5" y1="236.6" x2="666.5" y2="236.6" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="240.6" fill="#b06000">1/2 gap 64.50</text>
|
||||
<text x="672.5" y="237.2" fill="#b06000">1/2 gap 64.50</text>
|
||||
<line x1="36.5" y1="243.8" x2="666.5" y2="243.8" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="254.6" fill="#c00">SL 64.10</text>
|
||||
<text x="672.5" y="251.2" fill="#c00">SL 64.10</text>
|
||||
<line x1="36.5" y1="276.2" x2="666.5" y2="276.2" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="280.2" fill="#b06000">jos gap 62.30</text>
|
||||
<line x1="44.0" y1="330.2" x2="44.0" y2="346.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
@@ -840,12 +844,14 @@ se execută ca ordine de vânzare și împing prețul și mai jos.</p>
|
||||
<!--SVG:rezultate_bune_da-->
|
||||
<p><svg viewBox="0 0 767 436" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily</text>
|
||||
<line x1="666.5" y1="200.0" x2="671.5" y2="196.0" stroke="#188a3e" stroke-width="1"/>
|
||||
<line x1="666.5" y1="206.0" x2="671.5" y2="210.0" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="36.5" y1="92.0" x2="666.5" y2="92.0" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="96.0" fill="#1a5fb4">TP 57.90 = 2R</text>
|
||||
<line x1="36.5" y1="200.0" x2="666.5" y2="200.0" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="204.0" fill="#188a3e">intrare 53.40</text>
|
||||
<text x="672.5" y="200.0" fill="#188a3e">intrare 53.40</text>
|
||||
<line x1="36.5" y1="206.0" x2="666.5" y2="206.0" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="218.0" fill="#b06000">neckline 53.15</text>
|
||||
<text x="672.5" y="214.0" fill="#b06000">neckline 53.15</text>
|
||||
<line x1="36.5" y1="254.0" x2="666.5" y2="254.0" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="258.0" fill="#c00">SL 51.15</text>
|
||||
<line x1="44.0" y1="274.4" x2="44.0" y2="298.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
@@ -1378,16 +1384,20 @@ fără să dea un exemplu. Varianta de mai jos e construcția mea.</p>
|
||||
<!--SVG:condor-->
|
||||
<p><svg viewBox="0 0 678 290" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily</text>
|
||||
<line x1="546.5" y1="108.0" x2="551.5" y2="104.5" stroke="#1a5fb4" stroke-width="1"/>
|
||||
<line x1="546.5" y1="115.0" x2="551.5" y2="118.5" stroke="#777" stroke-width="1"/>
|
||||
<line x1="546.5" y1="213.0" x2="551.5" y2="209.5" stroke="#777" stroke-width="1"/>
|
||||
<line x1="546.5" y1="220.0" x2="551.5" y2="223.5" stroke="#1a5fb4" stroke-width="1"/>
|
||||
<line x1="36.5" y1="80.0" x2="546.5" y2="80.0" stroke="#6a3d9a" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="84.0" fill="#6a3d9a">call cumpărat 56.00</text>
|
||||
<line x1="36.5" y1="108.0" x2="546.5" y2="108.0" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="112.0" fill="#1a5fb4">call vândut 54.00</text>
|
||||
<text x="552.5" y="108.5" fill="#1a5fb4">call vândut 54.00</text>
|
||||
<line x1="36.5" y1="115.0" x2="546.5" y2="115.0" stroke="#777" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="126.0" fill="#777">+7% implicit 53.50</text>
|
||||
<text x="552.5" y="122.5" fill="#777">+7% implicit 53.50</text>
|
||||
<line x1="36.5" y1="213.0" x2="546.5" y2="213.0" stroke="#777" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="217.0" fill="#777">−7% implicit 46.50</text>
|
||||
<text x="552.5" y="213.5" fill="#777">−7% implicit 46.50</text>
|
||||
<line x1="36.5" y1="220.0" x2="546.5" y2="220.0" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="231.0" fill="#1a5fb4">put vândut 46.00</text>
|
||||
<text x="552.5" y="227.5" fill="#1a5fb4">put vândut 46.00</text>
|
||||
<line x1="36.5" y1="248.0" x2="546.5" y2="248.0" stroke="#6a3d9a" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="252.0" fill="#6a3d9a">put cumpărat 44.00</text>
|
||||
<line x1="44.0" y1="154.2" x2="44.0" y2="168.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
|
||||
@@ -331,16 +331,20 @@ ai un nivel concret pentru stop: sub zona apărată.
|
||||
<!--SVG:gap_pullback_da-->
|
||||
<svg viewBox="0 0 761 484" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily</text>
|
||||
<line x1="666.5" y1="193.4" x2="671.5" y2="188.2" stroke="#188a3e" stroke-width="1"/>
|
||||
<line x1="666.5" y1="197.0" x2="671.5" y2="202.2" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="666.5" y1="236.6" x2="671.5" y2="233.2" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="666.5" y1="243.8" x2="671.5" y2="247.2" stroke="#c00" stroke-width="1"/>
|
||||
<line x1="36.5" y1="92.6" x2="666.5" y2="92.6" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="96.6" fill="#1a5fb4">TP 72.50 = 2R</text>
|
||||
<line x1="36.5" y1="193.4" x2="666.5" y2="193.4" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="197.4" fill="#188a3e">intrare 66.90</text>
|
||||
<text x="672.5" y="192.2" fill="#188a3e">intrare 66.90</text>
|
||||
<line x1="36.5" y1="197.0" x2="666.5" y2="197.0" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="211.4" fill="#b06000">sus gap 66.70</text>
|
||||
<text x="672.5" y="206.2" fill="#b06000">sus gap 66.70</text>
|
||||
<line x1="36.5" y1="236.6" x2="666.5" y2="236.6" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="240.6" fill="#b06000">1/2 gap 64.50</text>
|
||||
<text x="672.5" y="237.2" fill="#b06000">1/2 gap 64.50</text>
|
||||
<line x1="36.5" y1="243.8" x2="666.5" y2="243.8" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="254.6" fill="#c00">SL 64.10</text>
|
||||
<text x="672.5" y="251.2" fill="#c00">SL 64.10</text>
|
||||
<line x1="36.5" y1="276.2" x2="666.5" y2="276.2" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="280.2" fill="#b06000">jos gap 62.30</text>
|
||||
<line x1="44.0" y1="330.2" x2="44.0" y2="346.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
@@ -760,12 +764,14 @@ se execută ca ordine de vânzare și împing prețul și mai jos.
|
||||
<!--SVG:rezultate_bune_da-->
|
||||
<svg viewBox="0 0 767 436" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily</text>
|
||||
<line x1="666.5" y1="200.0" x2="671.5" y2="196.0" stroke="#188a3e" stroke-width="1"/>
|
||||
<line x1="666.5" y1="206.0" x2="671.5" y2="210.0" stroke="#b06000" stroke-width="1"/>
|
||||
<line x1="36.5" y1="92.0" x2="666.5" y2="92.0" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="96.0" fill="#1a5fb4">TP 57.90 = 2R</text>
|
||||
<line x1="36.5" y1="200.0" x2="666.5" y2="200.0" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="204.0" fill="#188a3e">intrare 53.40</text>
|
||||
<text x="672.5" y="200.0" fill="#188a3e">intrare 53.40</text>
|
||||
<line x1="36.5" y1="206.0" x2="666.5" y2="206.0" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="218.0" fill="#b06000">neckline 53.15</text>
|
||||
<text x="672.5" y="214.0" fill="#b06000">neckline 53.15</text>
|
||||
<line x1="36.5" y1="254.0" x2="666.5" y2="254.0" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="672.5" y="258.0" fill="#c00">SL 51.15</text>
|
||||
<line x1="44.0" y1="274.4" x2="44.0" y2="298.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
@@ -1265,16 +1271,20 @@ fără să dea un exemplu. Varianta de mai jos e construcția mea.
|
||||
<!--SVG:condor-->
|
||||
<svg viewBox="0 0 678 290" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily</text>
|
||||
<line x1="546.5" y1="108.0" x2="551.5" y2="104.5" stroke="#1a5fb4" stroke-width="1"/>
|
||||
<line x1="546.5" y1="115.0" x2="551.5" y2="118.5" stroke="#777" stroke-width="1"/>
|
||||
<line x1="546.5" y1="213.0" x2="551.5" y2="209.5" stroke="#777" stroke-width="1"/>
|
||||
<line x1="546.5" y1="220.0" x2="551.5" y2="223.5" stroke="#1a5fb4" stroke-width="1"/>
|
||||
<line x1="36.5" y1="80.0" x2="546.5" y2="80.0" stroke="#6a3d9a" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="84.0" fill="#6a3d9a">call cumpărat 56.00</text>
|
||||
<line x1="36.5" y1="108.0" x2="546.5" y2="108.0" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="112.0" fill="#1a5fb4">call vândut 54.00</text>
|
||||
<text x="552.5" y="108.5" fill="#1a5fb4">call vândut 54.00</text>
|
||||
<line x1="36.5" y1="115.0" x2="546.5" y2="115.0" stroke="#777" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="126.0" fill="#777">+7% implicit 53.50</text>
|
||||
<text x="552.5" y="122.5" fill="#777">+7% implicit 53.50</text>
|
||||
<line x1="36.5" y1="213.0" x2="546.5" y2="213.0" stroke="#777" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="217.0" fill="#777">−7% implicit 46.50</text>
|
||||
<text x="552.5" y="213.5" fill="#777">−7% implicit 46.50</text>
|
||||
<line x1="36.5" y1="220.0" x2="546.5" y2="220.0" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="231.0" fill="#1a5fb4">put vândut 46.00</text>
|
||||
<text x="552.5" y="227.5" fill="#1a5fb4">put vândut 46.00</text>
|
||||
<line x1="36.5" y1="248.0" x2="546.5" y2="248.0" stroke="#6a3d9a" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="552.5" y="252.0" fill="#6a3d9a">put cumpărat 44.00</text>
|
||||
<line x1="44.0" y1="154.2" x2="44.0" y2="168.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
|
||||
@@ -311,7 +311,7 @@ tabelul de mai sus.</p>
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily</text>
|
||||
<line x1="356.0" y1="52.0" x2="356.0" y2="445.6" stroke="#bbb" stroke-dasharray="2 3"/>
|
||||
<line x1="36.0" y1="381.6" x2="356.0" y2="381.6" stroke="#b06000" stroke-width="2"/>
|
||||
<text x="682.0" y="386.6" fill="#b06000">pivot M6 73.10</text>
|
||||
<text x="682.0" y="386.1" fill="#b06000">pivot M6 73.10</text>
|
||||
<line x1="356.0" y1="260.3" x2="676.0" y2="260.3" stroke="#b06000" stroke-width="2"/>
|
||||
<text x="682.0" y="264.3" fill="#b06000">pivot M7 77.77</text>
|
||||
<line x1="356.0" y1="157.1" x2="676.0" y2="157.1" stroke="#1a5fb4" stroke-width="2"/>
|
||||
@@ -321,7 +321,7 @@ tabelul de mai sus.</p>
|
||||
<line x1="36.0" y1="316.6" x2="676.0" y2="316.6" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="682.0" y="320.6" fill="#188a3e">intrare 75.60</text>
|
||||
<line x1="36.0" y1="368.6" x2="676.0" y2="368.6" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="682.0" y="372.6" fill="#c00">SL 73.60 (sub HL)</text>
|
||||
<text x="682.0" y="372.1" fill="#c00">SL 73.60 (sub HL)</text>
|
||||
<line x1="44.0" y1="282.8" x2="44.0" y2="319.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="39.0" y="290.6" width="10" height="20.8" fill="#188a3e"/>
|
||||
<line x1="60.0" y1="264.6" x2="60.0" y2="298.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
|
||||
@@ -229,7 +229,7 @@ tabelul de mai sus.
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Exemplu construit (fără ticker) — daily</text>
|
||||
<line x1="356.0" y1="52.0" x2="356.0" y2="445.6" stroke="#bbb" stroke-dasharray="2 3"/>
|
||||
<line x1="36.0" y1="381.6" x2="356.0" y2="381.6" stroke="#b06000" stroke-width="2"/>
|
||||
<text x="682.0" y="386.6" fill="#b06000">pivot M6 73.10</text>
|
||||
<text x="682.0" y="386.1" fill="#b06000">pivot M6 73.10</text>
|
||||
<line x1="356.0" y1="260.3" x2="676.0" y2="260.3" stroke="#b06000" stroke-width="2"/>
|
||||
<text x="682.0" y="264.3" fill="#b06000">pivot M7 77.77</text>
|
||||
<line x1="356.0" y1="157.1" x2="676.0" y2="157.1" stroke="#1a5fb4" stroke-width="2"/>
|
||||
@@ -239,7 +239,7 @@ tabelul de mai sus.
|
||||
<line x1="36.0" y1="316.6" x2="676.0" y2="316.6" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="682.0" y="320.6" fill="#188a3e">intrare 75.60</text>
|
||||
<line x1="36.0" y1="368.6" x2="676.0" y2="368.6" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="682.0" y="372.6" fill="#c00">SL 73.60 (sub HL)</text>
|
||||
<text x="682.0" y="372.1" fill="#c00">SL 73.60 (sub HL)</text>
|
||||
<line x1="44.0" y1="282.8" x2="44.0" y2="319.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="39.0" y="290.6" width="10" height="20.8" fill="#188a3e"/>
|
||||
<line x1="60.0" y1="264.6" x2="60.0" y2="298.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
|
||||
@@ -22,9 +22,25 @@ Două stiluri de desen:
|
||||
candelă se suprapun.
|
||||
"""
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
def _check_dash(dash: str, cls: str) -> None:
|
||||
"""`dash` e un stroke-dasharray SVG ("4 3", "" etc.), nu o pozitie.
|
||||
|
||||
Garda exista pentru ca `Level(p, text, color, "left")` pune tacut "left"
|
||||
in `dash` in loc de `label_at`, iar SVG-ul iese fara linie punctata si
|
||||
fara nicio eroare. Trei agenti au pierdut timp pe asta pe 13.09.2026.
|
||||
"""
|
||||
if dash and not re.fullmatch(r"[\d.,\s]+", dash):
|
||||
raise ValueError(
|
||||
f"{cls}.dash={dash!r} nu e un stroke-dasharray. "
|
||||
f"Daca voiai pozitia etichetei, argumentul se cheama label_at "
|
||||
f"si se da pe nume: {cls}(..., label_at={dash!r})."
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Candle:
|
||||
o: float
|
||||
@@ -45,6 +61,11 @@ class Level:
|
||||
dash: str = "4 3"
|
||||
label_at: str = "right" # "right" | "left" — unde stă eticheta
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
_check_dash(self.dash, "Level")
|
||||
if self.label_at not in ("right", "left"):
|
||||
raise ValueError(f"Level.label_at={self.label_at!r}, astept 'right' sau 'left'")
|
||||
|
||||
|
||||
@dataclass
|
||||
class Mark:
|
||||
@@ -64,6 +85,9 @@ class MA:
|
||||
dash: str = ""
|
||||
text: str = ""
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
_check_dash(self.dash, "MA")
|
||||
|
||||
|
||||
@dataclass
|
||||
class Chart:
|
||||
|
||||
Reference in New Issue
Block a user