# lambda docker
## Docker
```
- docker-compose.yaml
- Dockerfile
- message.py
```
* docker-compose.yaml
```yaml=
version: '3'
services:
orderbook_docker:
build: ./
ports:
- '80:80'
#command: tail -f /dev/null #コンテナを立てっぱなしにできる
networks:
app_net:
ipv4_address: 172.30.0.2
networks:
app_net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.30.0.0/24
```
* Dockerfile
```dockerfile=
ARG FUNCTION_DIR="/home/pythontest"
FROM ubuntu:20.04
ARG FUNCTION_DIR
COPY ./app.py /home/pythontest/app.py
RUN apt-get update -y
RUN apt-get install -y g++ make cmake unzip libcurl4-openssl-dev apt-utils
RUN apt-get install -y python3.8
RUN apt-get install -y python3-pip
RUN pip3 install requests pandas tqdm boto3 matplotlib
RUN pip3 install --target ${FUNCTION_DIR} awslambdaric
#COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}
WORKDIR ${FUNCTION_DIR}
# Command can be overwritten by providing a different command in the template directly.
ENTRYPOINT [ "python3", "-m", "awslambdaric" ]
CMD ["app.lambda_handler"]
```
* `app.py`(シークレットとかはHackMDに公開しないように消してる)
```python=
import requests
import pandas as pd
import traceback
import time
import sys
import datetime
import matplotlib.pyplot as plt
import io
webhook_url = ""
class timeseries_lambda_nortify:
def chat_plot(self,ii):
"""
discordに画像送信
"""
while True:
try:
files_qiita = {
"favicon" : ( "favicon.png", ii),
}
headers = {'Content-Type': 'application/json'}
response = requests.post(webhook_url, files = files_qiita)
return
except Exception as e:
print(e)
time.sleep(60)
def ls_diff2(self):
"""
#api呼び出し、先物close、index close、LS、Frを集める
"""
retryt = 10
while (retryt<=100):
try:
#まずはlsデータを取得
logic_symbols = ["ETHUSDT","BTCUSDT"]
li1 = []
for symbol in logic_symbols:
lsapi = requests.get(f"https://api.bybit.com/v2/public/account-ratio?symbol={symbol}&period=1h&limit=50").json() #lsデータの1時間足取得
#取引所サーバ側の問題で、1時間足のデータ更新が上手くいっていない場合があるから、念のため最短の5分足の最新データを使う
ls_df = pd.DataFrame(lsapi["result"])
li1.append(ls_df)
ls_df = pd.concat(li1)
ls_df["buy_ratio"] = ls_df["buy_ratio"].apply(float) #ls比をfloat型に
ls_df["timestamp"] = ls_df["timestamp"].apply(int) #timestampをint型に
ls_df["date"] = ls_df["timestamp"].apply(lambda x: pd.to_datetime(x,unit="s")) #timestampデータから日付型データ作成
ls_df.sort_values(["symbol","timestamp"],inplace=True) #銘柄ごと、時刻ごとに並び替え
ls_df.reset_index(drop=True,inplace=True) #インデックス振り直し
#次にfunding rate取得
li1 = []
for symbol in logic_symbols:
#ls_api = requests.get(f"https://api.bybit.com/v2/public/funding/prev-funding-rate?symbol={symbol.replace('USDT','USD')}").json()
ls_api = requests.get(f"https://api.bybit.com/derivatives/v3/public/funding/history-funding-rate?category=linear&limit=200&symbol={symbol}").json()
#li1.append(ls_api["result"])
li1 += ls_api["result"]["list"]
fr_df = pd.DataFrame(li1)
fr_df.rename(columns={"fundingRate":"fr","fundingRateTimestamp":"timestamp"},inplace=True)
fr_df["timestamp"] = fr_df["timestamp"].apply(lambda x: int(int(x)/1000))
fr_df["fr"] = fr_df["fr"].apply(float)
ls_df = pd.merge(ls_df,fr_df,on=["timestamp","symbol"],how="outer") #ここでlsとfr結合しておく
#次に現先価格データ取得
li1,li2 = [],[]
now_t = datetime.datetime.now()
for symbol in logic_symbols:
for i in range(1,5):
startt = int(int(now_t.timestamp()) - 60*60*199*i) #1時間足で30日前まで、最新~720個前のデータがほしいけど200個前までしか取れない、だからfromのパラメータを順々にずらしていく
pri_spot = requests.get(f"https://api.bybit.com/public/linear/index-price-kline?symbol={symbol}&interval=60&from={startt}&limit=200").json()
pri_future = requests.get(f"https://api.bybit.com/public/linear/kline?symbol={symbol}&interval=60&limit=200&from={startt}").json()
pri_spot = pd.DataFrame(pri_spot["result"])
pri_future = pd.DataFrame(pri_future["result"])
li1.append(pri_spot)
li2.append(pri_future)
pri_spot = pd.concat(li1) #現物価格全データ結合
pri_future = pd.concat(li2) #先物価格全データ結合
pri_spot = pri_spot[["symbol","open_time","close"]].copy() #必要なカラムだけ抽出
pri_future = pri_future[["symbol","open_time","close"]].copy()
pri_df = pd.merge(pri_future, pri_spot, on=["symbol", "open_time"], suffixes=['', '_s']) #現物データと先物データを銘柄と時刻が一致しているもので結合、現物価格はclose_sという名前にする
pri_df["date"] = pri_df["open_time"].apply(lambda x: pd.to_datetime(x,unit="s")) #timestampを日付型に変更
pri_df.drop_duplicates(subset=["date","symbol"],inplace=True,keep="last") #重複データ削除
pri_df.sort_values(["symbol","open_time"],inplace=True) #並び替え
pri_df.reset_index(drop=True,inplace=True) #インデックス振り直し
pri_df[["close","close_s"]] = pri_df[["close","close_s"]].applymap(float) #価格データをfloat型に変換
pri_df["dev"] = (pri_df["close_s"]/pri_df["close"]-1)*100
pri_df["m_dev"] = pri_df["dev"].rolling(720).mean() #これで30日平均のデータになる
pri_df = pd.merge(pri_df, ls_df, on=["symbol","date"]) #現先価格データとlsデータの結合
#注文量計算
pri_df[["dev","m_dev","buy_ratio"]] = pri_df[["dev","m_dev","buy_ratio"]].applymap(lambda x: round(x*100,2))
pri_df["fr"] = pri_df["fr"]*100
return pri_df
except Exception as e:
traceback.print_exc()
time.sleep(retryt)
retryt *= 2
sys.exit()
def make_figure(self):
"""
dfをもとに画像作成
"""
pri_df = self.ls_diff2()
#銘柄ごとに
for sy, df in pri_df.groupby("symbol"):
std_date = df["date"][ df["date"].apply(lambda x: x.hour==16) ].max()
std_ls = df["buy_ratio"][df["date"]==std_date].iloc[0]
min_ls, max_ls = df["buy_ratio"].min(), df["buy_ratio"].max()
start_date, end_date = df["date"].min(), df["date"].max()
df["fr"].fillna(method='ffill',inplace=True)
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(211)
ax.plot(df["date"],df["close"],label="price")
ax.set_title(f"{sy}")
ax.set_ylabel("price [USD]",fontsize=12)
ax1 = ax.twinx()
ax1.plot(df["date"],df["fr"],label="fr",color="black",linestyle="--")
ax1.set_ylabel("fr [%]",fontsize=16)
lines1, labels1 = ax.get_legend_handles_labels()
lines2, labels2 = ax1.get_legend_handles_labels()
ax1.legend(lines1+lines2, labels1+labels2, framealpha=1, facecolor="white", loc=(0,0))
ax2 = fig.add_subplot(212)
ax2.plot(df["date"],df["buy_ratio"],label="buy ratio",color="orange")
ax2.hlines(y=std_ls, xmin=start_date, xmax=end_date, color="orange",linestyles="--")
ax2.vlines(x=std_date, ymin=min_ls, ymax=std_ls, color="orange",linestyles="--")
ax2.set_ylabel("buy ratio [%]",fontsize=16)
ax2.set_xlabel("date",fontsize=12)
ax3 = ax2.twinx()
ax3.plot(df["date"],df["dev"], label="index/future",color="black")
ax3.plot(df["date"],df["m_dev"], label="index/future 30day",color="red",linestyle="--")
ax3.set_ylabel("price dev [%]",fontsize=16)
lines3, labels3 = ax2.get_legend_handles_labels()
lines4, labels4 = ax3.get_legend_handles_labels()
ax3.legend(lines3+lines4, labels3+labels4, framealpha=1, facecolor="white", loc=(0,0))
img_data = io.BytesIO()
fig.savefig(img_data, format='png')
plt.close(fig)
files = img_data.getvalue()
self.chat_plot(files)
return
def lambda_handler(event, context):
tn = timeseries_lambda_nortify()
tn.make_figure()
```
## Dockerコマンド
Unix、WindosのGitbash前提の書き方
* `docker-compose up --build` `-d`つければバックグラウンド
* `docker ps -a` ID表示、
* `docker rm $(docker ps -aq)` $()内を変数としてコンテナ一括削除
* `docker rmi $(docker images -aq)` イメージ一括削除
* `docker exec -it 657 bash` 657は docke psとかで分かるIDの頭3桁
* `docker stop 657` コンテナ停止
## Lambda 環境構築
* [AWS SAM](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install-windows.html)
* [これ参考に](https://www.farend.co.jp/blog/2022/01/aws-lambda-container-image/)
* インストール後、power shell で`sam --version`でインストール確認
* `sam init`、[これ](https://dev.classmethod.jp/articles/sam-init-enable-x-ray-tracing/)見た感じいったんX-Rayはよくわからんけど追加コストかかるらしいから無効
* `sam init`で権限がない~みたいなエラー。管理者権限で実行してもだめ。[これ](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=powershell#enable-long-paths-in-windows-10-version-1607-and-later)を参考に以下のコマンド打ったらいけた。
```
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" `
-Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
```
* `sam init`
```shell
PS C:\Database\WorkDocker\saminit> sam init
You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
Choose an AWS Quick Start application template
1 - Hello World Example
2 - Multi-step workflow
3 - Serverless API
4 - Scheduled task
5 - Standalone function
6 - Data processing
7 - Infrastructure event management
8 - Serverless Connector Hello World Example
9 - Multi-step workflow with Connectors
10 - Lambda EFS example
11 - Machine Learning
Template: 1
Use the most popular runtime and package type? (Python and zip) [y/N]: N
Which runtime would you like to use?
1 - dotnet6
2 - dotnet5.0
3 - dotnetcore3.1
4 - go1.x
5 - graalvm.java11 (provided.al2)
6 - graalvm.java17 (provided.al2)
7 - java11
8 - java8.al2
9 - java8
10 - nodejs16.x
11 - nodejs14.x
12 - nodejs12.x
13 - python3.9
14 - python3.8
15 - python3.7
16 - ruby2.7
17 - rust (provided.al2)
Runtime: 14
What package type would you like to use?
1 - Zip
2 - Image
Package type: 2
Based on your selections, the only dependency manager available is pip.
We will proceed copying the template using pip.
Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]: N
Project name [sam-app]: orderbook2
```
[1](https://dev.classmethod.jp/articles/lambda-container-pkgfmt-with-sam-cli/)
[pypl](https://pypi.org/project/awslambdaric/)
[aws資格情報](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-envvars.html)Y
* まず、管理者実行のpowershellで以下の環境変数設定
```
$Env:AWS_ACCESS_KEY_ID=""
$Env:AWS_SECRET_ACCESS_KEY=""
$Env:AWS_DEFAULT_REGION="ap-northeast-1"
```
* `sam build`
* `sam local invoke` これでローカル稼働テスト
* `sam deploy --guided` これで対話式ガイドでデプロイ
終わり