9.1. Mô hình biểu đồ

9.1.1. Mô hình vai đầu vai (Head and Shoulders Pattern)

Mô hình vai đầu vai (Head and Shoulders) là một mô hình đảo chiều xu hướng phổ biến trong phân tích kỹ thuật, thường xuất hiện ở đỉnh một xu hướng tăng để báo hiệu khả năng đảo chiều thành xu hướng giảm. Nó bao gồm ba đỉnh, trong đó đỉnh ở giữa (đầu) cao nhất, hai đỉnh hai bên (vai) có chiều cao tương đương, và được nối với nhau bởi một đường gọi là đường viền cổ (neckline).

def detect_head_shoulder(self, df: pd.DataFrame, window: int = 10,tolerance: float = 0.01) -> pd.Series: ...

Tham số

Tên tham số
Ý nghĩa
Kiểu dữ liệu
Giá trị mặc định

df

Dataframe chứa các giá trị để xác định mô hình vai đầu vai (bắt buộc phải có các cột 'high', 'low', 'close')

pandas.Dataframe

window

Độ rộng nến để xác định các đỉnh của mô hình (đinh hoặc đáy cao nhất, thấp nhất trong độ rộng window nến ở 2 bên).

int

10

tolerance

Giá trị % ít nhất mà điểm đầu phải cao hơn 2 vai

float

0.01

Ví dụ:

pa = client.Pattern()
df["head_shoulder"] = pa.detect_head_shoulder(df, window=10, tolerance=0.01)
print(df)

Kết quả trả ra:

Mội pandas.Series sẽ đánh dấu các giá trị "Entry", "Left_Shoulder", "Left_Neck", "Head", "Right_Neck", "Right_Shoulder" tại các vị trí index trong DataFrame tương ứng được xác định là các đỉnh, đấy thỏa mãn điều kiện để tạo thành mô hình. Ví dụ:

username = "REPLACE_WITH_YOUR_USERNAME"
password = "REPLACE_WITH_YOUR_PASSWORD"

client = FiinSession(username=username, password=password).login()

df = client.Fetch_Trading_Data(
    realtime=False,
    tickers=["HPG"],
    fields=["high","low","close"],
    adjusted=True,
    by="1d",
    from_date="2024-01-01",
    to_date="2024-12-31"
).get_data()

pa = client.Pattern()
df["head_shoulder"] = pa.detect_head_shoulder(df)
print(df)

Sẽ trả ra dữ liệu xác định mô hình vai đầu vai từ ngày 24/05/2024 đến 10/07/2024, DataFrame kết quả trả ra như sau:

ticker
timestamp
high
low
close
head_shoulder

...

...

...

...

...

...

HPG

2024-04-23 00:00

21249.36

20794.83

20908.46

Entry

HPG

2024-04-24 00:00

21931.16

21022.1

21817.53

HPG

2024-04-25 00:00

21741.77

21438.75

21628.14

HPG

2024-04-26 00:00

21628.14

21249.36

21514.51

...

...

...

...

...

...

HPG

2024-05-23 00:00

24582.35

23832.38

24582.35

HPG

2024-05-24 00:00

24582.35

23749.05

24082.37

Left_Shoulder

HPG

2024-05-27 00:00

24415.69

23874.045

24082.37

HPG

2024-05-28 00:00

24332.36

23999.04

24290.695

HPG

2024-05-29 00:00

24374.03

23832.38

23832.38

HPG

2024-05-30 00:00

23790.72

23332.4

23540.725

Left_Neck

...

...

...

...

...

...

HPG

2024-06-17 00:00

24957.34

24165.7

24540.69

Head

...

...

...

...

...

...

HPG

2024-07-01 00:00

23749.05

23374.07

23624.06

Right_Neck

...

...

...

...

...

...

HPG

2024-07-10 00:00

24582.35

24124.04

24124.04

Right_Shoulder

...

...

...

...

...

...

Biểu đồ trực quan hóa:

username = "REPLACE_WITH_YOUR_USERNAME"
password = "REPLACE_WITH_YOUR_PASSWORD"

client = FiinSession(username=username, password=password).login()

df = client.Fetch_Trading_Data(
    realtime=False,
    tickers=["HPG"],
    fields=["high","low","close"],
    adjusted=True,
    by="1d",
    from_date="2024-01-01",
    to_date="2024-12-31"
).get_data()

pa = client.Pattern()
df["head_shoulder"] = pa.detect_head_shoulder(df)

# Xác định các điểm đầu, vai gáy trong dataframe để vẽ biểu đố
df["head_shoulder_points"] = np.select(
    [
        df["head_shoulder"].isin(["Left_Shoulder","Head","Right_Shoulder"]),
        df["head_shoulder"].isin(["Entry","Left_Neck","Right_Neck"])
    ],
    [df["high"], df["low"]],
    default=np.nan
)

# Xác định đường neckline
idx_entry = df.index[df['head_shoulder'] == 'Entry'][0]
idx_shoulder1 = df.index[df['head_shoulder'] == 'Left_Shoulder'][0]
idx_neck1 = df.index[df['head_shoulder'] == 'Left_Neck'][0]
idx_neck2 = df.index[df['head_shoulder'] == 'Right_Neck'][0]
idx_head = df.index[df['head_shoulder'] == 'Head'][0]

# tọa độ (x, y)
x1, y1 = idx_entry, df.loc[idx_entry, 'low']
x2, y2 = idx_shoulder1, df.loc[idx_shoulder1, 'high']
x3, y3 = idx_neck1, df.loc[idx_neck1, 'low']
x4, y4 = idx_neck2, df.loc[idx_neck2, 'low']

# hệ số góc và hệ số chặn
a1 = (y2 - y1) / (x2 - x1)
b1 = y1 - a1 * x1

a2 = (y4 - y3) / (x4 - x3)
b2 = y3 - a2 * x3

# giao điểm (x, y)
x_intersect = round((b2 - b1) / (a1 - a2))
y_intersect = a1 * x_intersect + b1

# --- Tìm điểm close đầu tiên nằm dưới L2 kể từ Right_Neck trở đi ---
break_idx = None
value_break = None
for i in range(idx_neck2, len(df)):
    y_line = a2 * i + b2
    if df.loc[i, 'close'] < y_line:
        break_idx = i
        value_break = y_line
        break

break_gap = df.loc[idx_head, 'high'] - value_break
target_idx = len(df) - 1
for i in range(break_idx, len(df)):
    if df.loc[i, 'close'] < value_break - break_gap:
        target_idx = i
        break

df["neck_line"] = None
df.loc[x_intersect, "neck_line"] = y_intersect
df.loc[break_idx, "neck_line"] = value_break
df.loc[break_idx, "head_shoulder_points"] = value_break
df['neck_line'] = df['neck_line'].apply(lambda x: np.nan if x is None else x)

# Chuyển timestamp
df['timestamp'] = pd.to_datetime(df['timestamp'], format='%Y-%m-%d %H:%M')
df.set_index('timestamp', inplace=True)

# Làm mượt (nối) giá trị head_shoulder để vẽ liền
df['head_shoulder_line'] = df['head_shoulder_points'].interpolate(method='linear')
df['neck_line'] = df['neck_line'].interpolate(method='linear')

# Chặn đoạn sau điểm cuối cùng có dữ liệu thật
last_valid = df['head_shoulder_points'].last_valid_index()
# last_valid_neck_line = df['neck_line'].last_valid_index()
df.loc[df.index > last_valid, 'head_shoulder_line'] = None
df.loc[df.index > last_valid, 'neck_line'] = None

# Tạo plot line
add_lines = [
    mpf.make_addplot(df['head_shoulder_line'], color='blue', width=1.5),
    mpf.make_addplot(df["neck_line"], color='blue', width=1.5, linestyle='--')
]

# Vẽ biểu đồ nến + line
fig, axes = mpf.plot(
    df[['open','high','low','close']],
    type='candle',
    style='yahoo',
    addplot=add_lines,
    title='Mô hình Vai - Đầu - Vai (liên tục)',
    figsize=(12,6),
    returnfig=True
)

# Vẽ đường dọc từ điểm cuối xuống break gap đơn vị giá
ax = axes[0]
ax.plot(
    [break_idx, break_idx],  # x: cùng timestamp
    [value_break, value_break - break_gap],        # y: từ giá trị xuống thấp hơn 2
    color='blue', linestyle='--', linewidth=1.2
)

ax.plot(
    [break_idx, target_idx],
    [value_break - break_gap, value_break - break_gap],
    color='blue', linestyle='--', linewidth=1.2
)

plt.show()

9.1.2. Mô hình vai đầu vai ngược (Inverse Head and Shoulders Pattern)

Mô hình vai đầu vai ngược (Inverse Head and Shoulders) là một mô hình phân tích kỹ thuật dùng để dự báo sự đảo chiều từ xu hướng giảm sang xu hướng tăng. Mô hình này bao gồm ba đáy, trong đó đáy ở giữa (đầu) là đáy thấp nhất, và hai đáy hai bên (vai trái, vai phải) cao hơn. Khi giá phá vỡ "đường viền cổ" (nối hai đỉnh giữa hai đáy) và có khối lượng giao dịch tăng mạnh, mô hình được xác nhận, cho thấy xu hướng tăng có thể bắt đầu.

def detect_inverse_head_shoulder(self, df: pd.DataFrame, window: int = 10, tolerance: float = 0.01) -> pd.Series: ...

Tham số

Tên tham số
Ý nghĩa
Kiểu dữ liệu
Giá trị mặc định

df

Dataframe chứa các giá trị để xác định mô hình vai đầu vai (bắt buộc phải có các cột 'high', 'low', 'close')

pandas.Dataframe

window

Độ rộng nến để xác định các đỉnh của mô hình (đinh hoặc đáy cao nhất, thấp nhất trong độ rộng window nến ở 2 bên).

int

10

tolerance

Giá trị % ít nhất mà điểm đầu phải cao hơn 2 vai

float

0.01

Ví dụ:

pa = client.Pattern()
df["head_shoulder"] = pa.detect_inverse_head_shoulder(df, window=10, tolerance=0.01)
print(df)

Last updated