Opublikowano:
Aktualizacja:
W poprzednim artykule zaprezentowano test strategii polegającej na algotradingu generowanego sygnałami przecinających się dwóch wartości średnich kroczących – wolnej oraz szybkiej. Dla przypomnienia poniżej przedstawiono kod źródłowy do analizy 1000 ostatnich świec.
import pandas as pd
import plotly.graph_objects as go
import matplotlib.pyplot as plt
df=pd.read_csv('/content/drive/My Drive/dane_historyczne/dax.csv')
df2=df.drop(['Wolumen'], axis=1)
df2=df2[-1000:]
l_usrednien_H=13
l_usrednien_L=3
df2['sr1'] =df2['Zamkniecie'].ewm(span=l_usrednien_H, adjust=False).mean()
df2['sr2'] =df2['Zamkniecie'].ewm(span=l_usrednien_L, adjust=False).mean()
df3=df2[l_usrednien_H:]
df3 = df3.reset_index(drop=True)
df3['cross'] =df3['sr2']>df3['sr1']
byk=[]
niedzwiedz=[]
for indeks in range(len(df3)):
if indeks>0 and df3['cross'].iloc[indeks]==1 and df3['cross'].iloc[indeks-1]==0:
byk.insert(indeks,df3.index[indeks])
for indeks in range(len(df3)):
if indeks>0 and df3['cross'].iloc[indeks]==0 and df3['cross'].iloc[indeks-1]==1:
niedzwiedz.insert(indeks,df3.index[indeks])
#zagrania na wzrost
ind_byk=[]
prof_byk=[]
for indeks1 in byk:
for indeks2 in niedzwiedz:
if indeks2>indeks1:
profit=df3['Zamkniecie'][indeks2]-df3['Zamkniecie'][indeks1]
prof_byk.insert(0,profit)
ind_byk.insert(0,indeks2)
break
dx = pd.DataFrame()
dx['indeks'] =ind_byk
dx['profit'] =prof_byk
#zagrania na spadek
bilans2=0
ind_niedzwiedz=[]
prof_niedzwiedz=[]
for indeks2 in niedzwiedz:
for indeks1 in byk:
if indeks1>indeks2:
profit=df3['Zamkniecie'][indeks1]-df3['Zamkniecie'][indeks2]
prof_niedzwiedz.insert(0,profit)
ind_niedzwiedz.insert(0,indeks1)
break
dy = pd.DataFrame()
dy['indeks'] =ind_niedzwiedz
dy['profit'] =prof_niedzwiedz
result = pd.concat([dx, dy])
dn=result.sort_values(by=['indeks'])
dn = dn.reset_index(drop=True)
bilans=[]
for indeks2 in range(len(dn)):
if indeks2>0:
bilans.insert(indeks2,dn['profit'][indeks2]+bilans[-1])
else:
bilans.insert(indeks2,dn['profit'][indeks2])
dn['bilans'] =bilans
x = dn['indeks']
y = dn['bilans']
plt.figure(figsize=(20, 5))
plt.plot(x, y)
plt.xlabel("Indeks świecy")
plt.ylabel("Zysk/Strata")
plt.show()
print("Całkowity bilans:","{:.1f}".format(sum(dn['profit'])), "punktów")
print("Liczba zamkniętych pozycji:",len(dn))
print("Największa całkowita strata:","{:.1f}".format(dn['bilans'].min()), "punktów")
print("Największy całkowity zysk:","{:.1f}".format(dn['bilans'].max()), "punktów")
Podstawowe parametry powyższej analizy to: średnia wolna – 13 świeczek oraz średnia szybka- 3 świeczki.
Bilans zastosowania algorytmu był dodatni i wynosił 12223 punkty. Pojawia się jednak pytanie – czy liczby uśredniania 13 i 3 są optymalne? A może należy zastosować np. liczby 10 i 5? Oczywiście można ręcznie wypisywać w powyższy kod różne średnie i notować wyniki w arkuszu kalkulacyjnym. Dla większej ilości parametrów będzie to bardzo czasochłonne.
Najprościej można dodać dwie pętle for i sprawdzić wszystkie rozwiązania z zdefiniowanego zakresu parametrów.
Poniżej znajduje się kod programu do przykładowego sprawdzenia, jakie parametry uśredniania są najlepsze:
l_usrednien_H_start=3
l_usrednien_H_stop=15
l_usrednien_H_krok=1
l_usrednien_L_start=2
l_usrednien_L_stop=14
l_usrednien_L_krok=1
optimum_df = pd.DataFrame(columns=range(l_usrednien_L_start,l_usrednien_L_stop+1,l_usrednien_L_krok))
for i in range(l_usrednien_L_start,l_usrednien_L_stop+1,l_usrednien_L_krok):
l_usrednien_L=i
lista=[]
for j in range(l_usrednien_H_start,l_usrednien_H_stop+1,l_usrednien_H_krok):
l_usrednien_H=j
if l_usrednien_H>l_usrednien_L:
df2['sr1'] =df2['Zamkniecie'].ewm(span=l_usrednien_H, adjust=False).mean()
df2['sr2'] =df2['Zamkniecie'].ewm(span=l_usrednien_L, adjust=False).mean()
df3=df2[l_usrednien_H:]
df3 = df3.reset_index(drop=True)
df3['cross'] =df3['sr2']>df3['sr1']
byk=[]
niedzwiedz=[]
for indeks in range(len(df3)):
if indeks>0 and df3['cross'].iloc[indeks]==1 and df3['cross'].iloc[indeks-1]==0:
byk.insert(indeks,df3.index[indeks])
for indeks in range(len(df3)):
if indeks>0 and df3['cross'].iloc[indeks]==0 and df3['cross'].iloc[indeks-1]==1:
niedzwiedz.insert(indeks,df3.index[indeks])
#zagrania na wzrost
ind_byk=[]
prof_byk=[]
for indeks1 in byk:
for indeks2 in niedzwiedz:
if indeks2>indeks1:
profit=df3['Zamkniecie'][indeks2]-df3['Zamkniecie'][indeks1]
prof_byk.insert(0,profit)
ind_byk.insert(0,indeks2)
break
dx = pd.DataFrame()
dx['indeks'] =ind_byk
dx['profit'] =prof_byk
#zagrania na spadek
bilans2=0
ind_niedzwiedz=[]
prof_niedzwiedz=[]
for indeks2 in niedzwiedz:
for indeks1 in byk:
if indeks1>indeks2:
profit=df3['Zamkniecie'][indeks1]-df3['Zamkniecie'][indeks2]
prof_niedzwiedz.insert(0,profit)
ind_niedzwiedz.insert(0,indeks1)
break
dy = pd.DataFrame()
dy['indeks'] =ind_niedzwiedz
dy['profit'] =prof_niedzwiedz
result = pd.concat([dx, dy])
dn=result.sort_values(by=['indeks'])
dn = dn.reset_index(drop=True)
bilans=[]
for indeks2 in range(len(dn)):
if indeks2>0:
bilans.insert(indeks2,dn['profit'][indeks2]+bilans[-1])
else:
bilans.insert(indeks2,dn['profit'][indeks2])
dn['bilans'] =bilans
x = dn['indeks']
y = dn['bilans']
lista.insert(len(lista),sum(dn['profit']))
else:
lista.insert(len(lista),nan)
optimum_df[l_usrednien_L]=lista
optimum_df.index = pd.RangeIndex(l_usrednien_H_start,l_usrednien_H_stop+1,l_usrednien_H_krok)
def simple_median_style(s: pd.Series, true_css: str, false_css: str = '') -> np.ndarray:
return np.where(s >= optimum_df.max().max(), true_css, false_css)
display(optimum_df.style.apply(simple_median_style, true_css='background-color: lightgreen'))
W rezultacie otrzymano tabelę wyników. Największe dodatni bilans transakcji osiągamy w dwóch przypadkach (zaznaczonych w tabeli na zielono):
1. Dla średniej wolnej równej 15 świec oraz średniej szybkiej 4 świece.
2. Dla średniej wolnej równej 15 świec oraz średniej szybkiej 5 świece.
W obu przypadkach algorytm uzyskałby bilans 1415 punktów.
Symbolem “nan” oznaczono zakres parametrów dla których wartość średniej wolnej jest mniejsza lub równa wartości średniej szybkiej (co jest sprzeczne z założeniami strategii).
© 2024 All Rights Reserved.
Cookie | Duration | Description |
---|---|---|
cookielawinfo-checkbox-analytics | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics". |
cookielawinfo-checkbox-functional | 11 months | The cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional". |
cookielawinfo-checkbox-necessary | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary". |
cookielawinfo-checkbox-others | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other. |
cookielawinfo-checkbox-performance | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance". |
viewed_cookie_policy | 11 months | The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data. |
Kopiowanie wszystkich kodów tylko dla użytkowników PREMIUM.