PYTHON/Kiwoom Open API

키움증권 Open API - 거래 내역 조회하기 (4)

이제 "주문구분"의 값이 무엇인가에 따라 데이터를 다른 곳에 입력하기만 하면 거래 내역은 모두 조회하게 된다.

 

 

주문 구분에 따라 데이터 입력하기 : def opw00007(trcode, recordname)

지난 게시글에서 현금 매수와 현금 매도까지 구분해두었다. 다만 이제 본인이 제작한 것은 분할매수의 알고리즘을 가지고 있다고 가정했을 경우에 필요한 데이터들이기 때문에, 매수 데이터가 발생했을 때 해당 매수 거래가 첫 번째 매수인지 두 번째 매수인지를 구분해야 할 것이다.

그러기 위해서는 앞서 제작했던   self.temporary_hold_account  변수의   ['first_buy_date']  또는   ['first_buy_price']   ['first_buy_quan']  칼럼 안에 데이터가 있는지만 확인해주면 된다.(셋 중 아무거나 사용해도 된다.)
※ 아래는 코드가 너무 길기 때문에 일부분은 생략하고, 현금매수와 현금매도 구분에 따른 부분만 업로드하였다.

다섯 번째 줄을 보면   ['first_buy_quan']  , 즉 첫 번째 매수 수량이 0이라면 매수 데이터가 없는 종목이기 때문에 첫 번째 매수 데이터에 해당하는   ['first_buy_']  에 데이터들을 입력해주고,   ['first_buy_quan']  의 값이 0이 아니라면 첫 번째 매수 데이터가 입력되어 있는 상태이기 때문에 두 번째 매수 데이터에 해당하는   ['second_buy_']  에 데이터들을 입력해주는 것이다. 

if order_gubun == "현금매수":
	self.temporary_hold_account.loc[idx, 'item_code'] = real_item_code		## item_Code 안에 종목 코드 입력
	self.temporary_hold_account = self.temporary_hold_account.fillna(0)		## 비어 있는 칸에 0을 입력

	if self.temporary_hold_account.loc[idx, 'first_buy_quan'] == 0:			## 첫 매수 데이터가 0이라면
		self.temporary_hold_account.loc[idx, 'first_buy_quan'] = trade_num
		self.temporary_hold_account.loc[idx, 'first_buy_price'] = trade_price
		self.temporary_hold_account.loc[idx, 'first_buy_date'] = self.opw00007_day

	elif self.temporary_hold_account.loc[idx, 'first_buy_quan'] != 0:		## 첫 매수 데이터가 0이 아니라면
		self.temporary_hold_account.loc[idx, 'second_buy_quan'] = trade_num
		self.temporary_hold_account.loc[idx, 'second_buy_price'] = trade_price
		self.temporary_hold_account.loc[idx, 'second_buy_date'] = self.opw00007_day

if order_gubun == "현금매도":
	pass

 

그렇다면 이제 현금매도 부분도 한 번 작성해보도록 하자. 현금매도의 경우에는 현금매수와 다른 점이 있는데, 바로 손절매 데이터가 입력된다는 것이다. 즉, 매도 데이터가 발생하는 순서에 따라 입력하기가 어렵다는 것이다. 따라서 우리는 특정 현금매도 거래가 손절매 거래인지 아니면 수익 거래인지를 구분해주어야 하는데, 그 기준이 되는 가장 중요한 것은 가격이다.

우리는 특정 거래가 체결된 가격, 즉 체결가격을   trade_price  라는 변수 안에 입력해주었기 때문에 해당 데이터와 기존에 매수했던 가격(첫 매수는   ['first_buy_price']  , 두 번째 매수는   ['second_buy_price']  )과 비교하여 매수 가격보다 낮다면 해당 거래 데이터는 손절매 데이터로 볼 수 있는 것이다. 반대는 말 그대로 손절매가 아닌 수익 거래이기 때문에 매도 데이터를 입력해주면 되고, 그 매도 데이터 역시 첫 번째 매도가 이루어진 이력이 있는가 없는가에 따라(12번째 줄 else:문 하단부의 if문과 elif문) 데이터를 달리 입력해주면 된다.

if order_gubun == "현금매도":

	## 손절매인 경우, 매수 가격보다 낮을 것
	if (trade_price < self.temporary_hold_account.loc[idx, 'first_buy_price']) or (trade_price < self.temporary_hold_account.loc[idx, 'second_buy_price']):
		self.temporary_hold_account.loc[idx, 'cut_sell_quan'] = trade_num
		self.temporary_hold_account.loc[idx, 'cut_sell_price'] = trade_price
		self.temporary_hold_account.loc[idx, 'cut_sell_date'] = self.opw00007_day
		self._run_psb29_sub2(real_item_code)

	## 낮지 않기 때문에 수익 거래에 해당함
	else:
		## 매도 이력이 없는 경우
		if self.temporary_hold_account.loc[idx, 'first_sell_quan'] == 0:
			self.temporary_hold_account.loc[idx, 'first_sell_quan'] = trade_num
			self.temporary_hold_account.loc[idx, 'first_sell_price'] = trade_price
			self.temporary_hold_account.loc[idx, 'first_sell_date'] = self.opw00007_day
            
		## 첫 매도가 이루어진 경우
		elif self.temporary_hold_account.loc[idx, 'first_sell_quan'] != 0:
			self.temporary_hold_account.loc[idx, 'second_sell_quan'] = trade_num
			self.temporary_hold_account.loc[idx, 'second_sell_price'] = trade_price
			self.temporary_hold_account.loc[idx, 'second_sell_date'] = self.opw00007_day

 

 


728x90

 

 

거래 내역 조회 시 반드시 작성해주어야 하는 부분

사실 위 내용만으로는 모든 코드 제작이 완료된 것은 아니다. 당장은 오류가 없을 수 있고, 평생 오류를 발견하지 못하고 사용할 수도 있지만, 오류가 발생한지도 모른 채 사용하게 될 수 있다. 오류가 발생할 수 있는 부분은 바로 매도 부분이다.

우리가 제작한 거래 내역 데이터를 조회하는 코드는 다음과 같은 구조로 이루어진다.

위의 세 가지 경우 중, 우리가 제작한 코드가 정상적으로 동작하는 경우는 가장 맨 아래에 있는 경우밖에 없다. 왜냐하면 10일 간의 데이터만 조회할 수 있기 때문이다. 즉, 우리가 제작한 코드는 오류가 발생할 수 있다. 다만 프로그램 상 오류는 없다. 결과 데이터 상의 오류만 있을 뿐이다. 

여기서 우리는 조회 범위로 설정한 10일 이전에 발생한 데이터는 조회하지 않기 때문에, 실제로 첫 번째 경우에는 매수는 하지도 않았는데 손절매를 한 경우가 될 것이고 두 번째 경우에는 150주와 150주를 매수한 후 300주를 매도했으나 조회 범위의 문제로 인해 150주만 매수했는데 300주를 매도하는 창조경제적인 데이터를 만들어낼 것이다.

이 문제는 의외로 간단하게 해결할 수 있다. 바로, "현금매도" 데이터가 발생했고 해당 거래가 손절 거래인가 수익 거래인가를 판단하기 전에 앞서, 해당 종목을 매수했었는가를 확인해보면 된다. 해당 종목을 매수했었다면   self.temporary_hold_account  변수 내에 해당 종목코드 데이터가 있을 것이고 매수하지 않았다면 종목코드 데이터가 없을 것이다. 

if order_gubun == "현금매도":
	if real_item_code in self.temporary_hold_account['item_code'].to_list():  ## 매도 데이터를 입력하기 위해서는 매수 데이터가 존재해야 함

		## 손절매인 경우, 매수 가격보다 낮을 것
		if (trade_price < self.temporary_hold_account.loc[idx, 'first_buy_price']) or (trade_price < self.temporary_hold_account.loc[idx, 'second_buy_price']):
			self.temporary_hold_account.loc[idx, 'cut_sell_quan'] = trade_num
			self.temporary_hold_account.loc[idx, 'cut_sell_price'] = trade_price
			self.temporary_hold_account.loc[idx, 'cut_sell_date'] = self.opw00007_day

		## 낮지 않기 때문에 수익 거래에 해당함
		else:
			## 매도 이력이 없는 경우
			if self.temporary_hold_account.loc[idx, 'first_sell_quan'] == 0:
				self.temporary_hold_account.loc[idx, 'first_sell_quan'] = trade_num
				self.temporary_hold_account.loc[idx, 'first_sell_price'] = trade_price
				self.temporary_hold_account.loc[idx, 'first_sell_date'] = self.opw00007_day
            
			## 첫 매도가 이루어진 경우
			elif self.temporary_hold_account.loc[idx, 'first_sell_quan'] != 0:
				self.temporary_hold_account.loc[idx, 'second_sell_quan'] = trade_num
				self.temporary_hold_account.loc[idx, 'second_sell_price'] = trade_price
				self.temporary_hold_account.loc[idx, 'second_sell_date'] = self.opw00007_day

 

자, 이제 세 가지 경우 중 첫 번째 경우에 해당하는 사지도 않은 종목을 손절매하는 오류는 해결했다. 그렇다면 이제 매수한 데이터가 조회 범위에 걸쳐 나뉘어 있는 경우, 즉 150주를 샀는데 300주를 매도하는 오류를 해결해보도록 하자. 이것 역시 위와 같이 단순하게 하나의 함수만 제작해주면 된다.

 

창조 경제 해결하기 : def _run_psb29_sub2(item_code)

해당 함수 내에서 종목 코드 변수(  item_code  )가   self.temporary_hold_account  변수 내에서 갖는 인덱스 번호(  idx  )를 얻은 후에, 해당 인덱스 번호에 해당하는 데이터 열에서   ['first_buy_quan']   ['second_buy_quan']   ['first_sell_quan']   ['second_sell_quan']   ['cut_sell_quan']  의 데이터를 모두 계산하여   hold_quan  변수 안에 해당 데이터를 입력한다. 

def _run_psb29_sub2(self, item_code):
	idx = self.temporary_hold_account.index[self.temporary_hold_account['item_code'] == item_code]
	hold_quan = self.temporary_hold_account.loc[idx, 'first_buy_quan'] + self.temporary_hold_account.loc[idx, 'second_buy_quan'] - self.temporary_hold_account.loc[idx, 'first_sell_quan'] - self.temporary_hold_account.loc[idx, 'second_sell_quan'] - self.temporary_hold_account.loc[idx, 'cut_sell_quan']

 

이제 이   hold_quan  이라는 변수 안에 어떤 데이터가 입력되어 있는가에 따라 데이터 처리를 달리하면 된다.

  • hold_quan이 0인 경우 : 정상 데이터(매수·매도 데이터가 동일)
  • hold_quan이 0보다 큰 경우 : 정상 데이터(매도 데이터가 부족함)
  • hold_quan이 0보다 작은 경우 : 비정상 데이터(매수 데이터가 부족함)

첫 번째와 두 번째의 경우에는 데이터가 정상적이므로 아무런 상관이 없으나, 세 번째의 경우에는 매수 수량(150주)보다 매도 수량(300주)이 더 클 경우에 나타나는 현상이므로 해당 데이터는 삭제를 해주는 것이 맞다. 즉, 해당 데이터는 거래 내역에 포함하지 않고 새롭게 다시 조회한다는 것이다.

def _run_psb29_sub2(self, item_code):
	idx = self.temporary_hold_account.index[self.temporary_hold_account['item_code'] == item_code]
	hold_quan = self.temporary_hold_account.loc[idx, 'first_buy_quan'] + self.temporary_hold_account.loc[idx, 'second_buy_quan'] - self.temporary_hold_account.loc[idx, 'first_sell_quan'] - self.temporary_hold_account.loc[idx, 'second_sell_quan'] - self.temporary_hold_account.loc[idx, 'cut_sell_quan']
    
	if (int(hold_quan) == 0) or (int(hold_quan) > 0):
		pass
	elif int(hold_quan) < 0:
		self.temporary_hold_account = self.temporary_hold_account.drop(index=idx).reset_index(drop=True)

 

이제 다시   def _run_psb29_sub1()  함수 내에서   print(self.temporary_hold_account)  를 사용해보면, 결과 데이터 상에서 오류가 없는 거래 데이터를 확인할 수 있을 것이다.

 

 

 

 

 

 


728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.