애들센스


VBA의 파이썬 따라잡기 오피스/VBA/Office.JS

파이썬의 map() 함수는 built-in 함수로 list 나 dictionary 와 같은 데이터를 받아 개별요소를 함수의 인자로 전달하여 결과를 list로 형태로 반환해 주는 함수이다. 글로 설명하면
def func(x):
  return x * 2
func()는 평범한 파이썬 함수로 매개변수로 받은 정수를 두배로 곱하여 반환해 주는 함수이다.
이 함수에 인자를 map() 함수를 이용해 전달해 보자.
>>> map( func, [1, 2, 3, 4] )
[2, 4, 6, 8]
위와 같이 map() 함수는 for문과 같은 반복문을 사용하지 않아도 지정한 함수로 매개변수를 여러 번 전달해 그 결과를 리스트로 뽑아 주는 유용한 함수이다. VBA는 이게 매우 부럽다. 남들은 한 줄로 간결하게 처리할 수 있는 데, VBA는 아직도 여러 줄의 반복문 블럭을 만들어야 한다. 그래서 흉내를 내보았다. 핵심은 Application.run() 이다.
Sub demoMap()
Dim m

m = map("func", Array(1, 2, 3, 4))

Debug.Print m(0); m(1); m(2); m(3);
End Sub

Function func(x)
func = x * 2
End Function

Function map(f As String, A As Variant) As Variant
'assumes that A is a 1-dimensional variant array
'and f is the name of a function that can be applied to it

Dim i As Long
Dim m As Variant

ReDim m(LBound(A) To UBound(A))
For i = LBound(A) To UBound(A)
m(i) = Application.Run(f, A(i))
Next
map = m
End Function
어떠신가? 그럴 듯 하지 아니한 가?


50만원이 100만원 되려면 몇 년이 걸릴 까? 펀드

이자율 1%일 때 50만원이 그 두 배인 100만원이 되려면 몇 년이 걸릴까? 아마 화성으로 우주선을 보내는 것이 더 빠를지도 모르겠다. n이 두 배가 되기 위해 필요한 시간(연)이라면 다음과 같이 식을 설정할 수 있다.

500000 * ( 1 + 0.01) ^n = 1000000

위의 식을 푸는 핵심은 양변에 로그를 씌우는 것이다. 그래서 아래와 같이 전개하면;
Log 500000 * ( 1 + 0.01) ^n = Log10^6
Log 1000000/2 + n * Log 1.01 = 6
Log 10^6 - Log 2 + n * Log 1.01 = 6
6 - Log 2 + n * Log 1.01 = 6
n * Log 1.01 = Log 2
n * (0.004321) = 0.30103
n = 69.66(년)

Log 값을 구하려면 계산기가 필요하지만, 그래도 눈에 가시같은 지수 n 을 쉽게 구할 수 있는 방법이다.

고인물같은 재무함수 오남용 후기 오피스/VBA/Office.JS

위키백과에서 정의한 현재가치는 미래에 얻게 될 확실한 부(富)의 가치를 현재의 가치로 환산한 값이다.
1기간 후부터 n기간까지의 미래에 일정한 현금흐름이 반복된다면 이를 현재가치로 환산하는 식은 다음과 같다.

엑셀의 PV함수 사용시 주의할 점은 매개변수중 pmt의 부호이다. pmt는 기간 동안 일정하게 지금 받거나 납입하는 금액을 말하는데, 현금이 들어오는 경우는 "+", 나가는 경우면 "-" 이다. 그리고 그 결과는 pmt의 부호방향과 반대이다.

가령 PV(0,1,-3) = 3, PV(0,1,3) = -3 이다.

그런데 PV공식을 보면 여러 개의 할인된 현금흐름(CF)이 ➕로 연결되어 있다. 만일 + 로 연결한 현금흐름에서 r=0이면 분모가 1이 되어 그 결과는 CF*n 이 된다. 결국 CF는 n기간동안 상수이고 , n 역시 상수이므로 단순곱셈이다. 그래서 3 곱하기 4는 12인데(구구단을 외우다니...처..천잰데..), PV를 이용하면 PV(0,3,4) = -12 이다. 엑셀의 PV함수 특성상 부호방향이 반대일 뿐이다. 즉 PV(0,1,1) = -1이고 PV(0,1,-1) = 1이다.

그래서 PV(0,1,PV(0,3,4))는 3 곱하기 4의 결과와 같다. 처음 나오는 PV는 부호를 변경하기 위한 것이고, 두 번째 PV는 곱셈연산을 한다. 곱셈을 참 어렵게 한다~ 그러나 현금흐름이 스칼라값이 아니라 배열이나 벡터와 같은 경우라면 한번에 여러 개의 곱셈연산을 하는 셈이 된다. 다음은 PV()를 이용하여 배열의 각 원소끼리 곱셈을 하는 코드이다.
Dim X, Y, Mult

X = Array(Array(1, 3), Array(2, 4))
Y = Array(1, 2)

With Application
    Mult = .PV(, 1, .PV(, X, Y))
End With
주의할 점은 Worksheetfunction.PV가 아니라 Application.PV를 사용해야 한다. Worksheetfunction.PV는 타입미스매치에러를 낸다.
위의 계산은 Y배열의 원소 1과 2를 배열 X내 1번째 배열 원소 1, 3에 곱하고, 다시 배열 X내 2번째 배열 원소 2, 4에 곱하는 것이다. 즉 원소대 원소 곱셈이다.
  • 배열Y 원소와 배열X의 1번째 배열원소간 곱셈 : 1*1, 2*3
  • 배열Y 원소와 배열X의 2번째 배열원소간 곱셈 : 1*2, 2*4
비슷한 방법으로 덧셈도 할 수 있다.
Add = .Pmt(, -1, X, Y)
그리고 다음과 같이 몇 가지 연산을 할 수 있는데, 머리 아프니 고만 알아보자.
연산
코드
X-Y
SLN(x, y, 1)
X/Y
SLN(x, y)
X^Y
Power(x, y)
X\Y
Quotient(x, y)
X=Y
Delta(x, y)
X<=Y
GeStep(x, y)














VBA 배열에 앙심을 품은 자

언제부터 인지는 모르겠지만 VBA 배열을 다루는 게 은근 재미있다. 그래서 어떻게 괴롭힐까 고민을 한다. 벡터연산이 없는 VBA을 갖고, 비스무리한 걸 만드는 데 ()희열을 느낄지도 모른다. 이른 바 VBA 변태~

몇 달 전에 스택오버플로 포스팅을 하나 북마크 해두고 나중에 봐야지 했는데, 이번에 코드를 함 뜯어 볼 참이다. 코드는 다음과 같다. 코드는 같은 길이, 같은 타입을 가진 두 개의 배열을 가지고 각 배열의 매칭되는 원소끼리 곱하는 짓거리이다.

코드의 핵심은
z = [GetX()*GetY()]

이다.

GetX()와 GetY()는 전역변수인 X, Y 배열을 돌려주는 역할만 한다. []는 'Square brackets'라고 부르는 데, 우리말로는 꺽쇠(마당쇠같은 머슴이름 아님). 이것은 벡터연산의 핵심인 Evaluate함수의 줄임말로 보면 된다.

expression.Evaluate (Name)
A formula or the name of the object, using the naming convention of Microsoft Excel.
The length of the name must be less than or equal to 255 characters.

[]는 셀 참조를 하는 용도로도 사용한다. 가령 A1 셀을 참조하기 위해서는 Range("A1")이라고 하지만 간단히 [A1]으로 써도 된다. A1과 "A1"은 다른 것이다. A1은 실제 해당 셀을 가리키는 개체상수 정도로 보면 되고, "A1"은 그냥 문자열 상수이다.

Evaluate()함수는 문자열로 전달한 수식이나 함수 등을 계산하는 함수이다.
여기에 들어갈 요소는 엑셀에서 사용가능한 것들, 문자열, 숫자, 배열상수, 연산자, 수식, 함수 등이다. 다음은 마이크로소프트 오피스데브센터에 있는 Evaluate() 사용 예이다.
[a1].Value = 25 
Evaluate("A1").Value = 25

trigVariable = [SIN(45)]
trigVariable = Evaluate("SIN(45)")

Set firstCellInSheet = Workbooks("BOOK1.XLS").Sheets(4).[A1]
Set firstCellInSheet = _
Workbooks("BOOK1.XLS").Sheets(4).Evaluate("A1")
[]안에 배열 X, Y를 직접 넣으면 되지 않을 까 싶지만, 이 배열변수들은 엑셀이 아닌 VBA의 요소이다. 따라서 변수를 넣으면 타입미스매치 에러가 난다.

GetX(), GetY()함수는 엑셀 워크시트에서도 사용가능한 요소이다. 그러므로 Evaluate()함수에서 사용가능한 것이고 둘 사이에 있는 * 는 곱셈연산자인데, 이것 역시 엑셀에서 통용되는 연산자 기호이다.

그래서 X,Y를 전역변수로 두고, 이 변수를 그대로 전달만 해주는 매개체이다. 얘네들은 Evaluate()함수에서 사용가능한 자격이 있기 때문이다.
Dim X, Y

Function GetX(): GetX = X: End Function
Function GetY(): GetY = Y: End Function

Sub MultiplyArrays()
Dim z

X = Array(1, 2, 3, 4, 5)
Y = Array(1, 2, 3, 4, 5)

' []가 과연 뭘까요?
' 변수 X, Y를 직접 사용하지 않고 GetX(), GetY() 함수를 사용할까요?
z = [GetX()*GetY()]

' 합계도 한번 구해 보고,
Debug.Print WorksheetFunction.Sum(z)

' 엑셀 워크시트로 출력도 해본다
Range("A1").Resize(UBound(X)) = WorksheetFunction.Transpose(X)
Range("B1").Resize(UBound(Y)) = WorksheetFunction.Transpose(Y)
Range("C1").Resize(UBound(z)) = WorksheetFunction.Transpose(z)
End Sub
예를 하나 더 보자.
이번에는 배열상수값을 사용한 예이다. {"Zip", "22150";"City", "Springfield"; "State", "VA"}는 엑셀에서 지원하는 상수포맷을 따른다. 마치 JSON개체처럼 보이지만 세미콜론(;)으로 행이 구분되고 컴마(,)로 컬럼이 구분되는 행렬형태의 2차원 배열상수이다.
Sub UsingSquareBrackets()
'The [...] syntax is a shortcut for Application.Evaluate()

Dim vArray As Variant
Dim iCounter As Long

' {}는 무엇일까?
vArray = [{"Zip", "22150";"City", "Springfield"; "State", "VA"}]

For iCounter = LBound(vArray, 1) To UBound(vArray, 1)
Debug.Print vArray(iCounter, 1), vArray(iCounter, 2)
Next

End Sub
Evaluate()함수를 사용하지 않는 경우 어떻게 할까? 위의 코드에서는 배열에 입력해야 하는 값들이 모두 상수여서 활용성이 떨어진다. 다음은 Evaluate()함수를 사용하지 않는 평범한 VBA코드이다. 코드가 약간 길어진다.
Sub UsingArrayInArray()
Dim vArray As Variant

Dim iZip As Long
Dim sCity As String
Dim sState As String

iZip = 22150
sCity = "Springfield"
sState = "VA"
vArray = Array(Array("Zip", iZip), Array("City", sCity), Array("State", sState))

Dim iCounter As Long

For iCounter = LBound(vArray, 1) To UBound(vArray, 1)
Debug.Print vArray(iCounter)(0), vArray(iCounter)(1)
Next

End Sub


쟁고파이썬쉘을 좀 더 편하게 사용하기 파이썬/쟁고


어드민 사이트는 UI화면을 통해 사용자가 CRUD(Create, Read, Update, Delete)를 편하게 작업할 수 있게 해주지만, 다양한 데이터 관리를 위해서는 쟁고파이썬쉘을 이용하는 것이 편리하다. 특히 뷰를 작성하기 위한 테스트 코드를 작성할 때 유용한데, 쟁고파이썬쉘은 manage.py에서 정의한 DJANGO-SETTINGS_MODULE속성을 이용하여 미리 settings.py 모듈을 임포트한다.

다만 문제라면 >>> 프롬프트에서 작업하는 것이 고역이다. 그래서 스택오버플로에서 찾아보니 다분히 파이썬스러운 답이 있는 데, 여러 대안중 가장 맘에 드는 것은
$ ./manage.py shell
...
>>> exec(open('myscript.py').read())
이다.

(엑셀도감) 참조하는 넘, 참조당하는 넘 오피스/VBA/Office.JS

엑셀 사용하면서 수식을 사용하지 않는 사람은 없는 데, 수식에 걸어둔 셀로 이동하거나 본인을 참조한 셀로 이동하는 단축키이다.
그러나 수식에서 참조하는 모든 셀로 이동하는 것은 아닌 듯, 첫 셀이나 셀 영역으로 이동한다.

내침 김에 한글 팁 하나 더 오피스/VBA/Office.JS

오피스를 많이 사용하다가 한글을 사용하려니 불편한 점이 몇 가지 있어 비슷한 기능을 찾아 보게 된다. 이번에는 표안의 값을 수식으로 자동계산되는 기능이다. 워드에도 비슷한 기능이 있는 걸로 기억하는 데, 한글은 이 기능을 [블록 계산식]이라고 한다.

위와 같은 표에서 [매각소유일수]는 보유한 주식을 연속으로 처분하는 데 필요한 시간을 의미한다. 20일간의 평균거래량으로 보유한 주식수를 나눈 값이다. 사실 이런 예상치가 실제와는 큰 차이가 있을 걸로 보이는데, 그 얘기는 주제에 벗어나므로 여기까지만...

엑셀처럼 A,B,C 등 알파벳으로 컬럼을 표시하고 1,2,3 등 숫자로 행을 표시한다. 그래서 표의 최상단 왼쪽 셀은 A1이다. 그리고 같은 행의 오른쪽 컬럼은 B1, C1 등으로 표시하여 수식을 표현할 수 있다. 이런 주소 표현은 엑셀의 절대주소 표시방식과 비슷하다. 상대적인 주소 표현은 [쉬운 범위] 드랍다운박스에서 고를 수 있다. [함수]드랍다운 박스에서는 여러 함수가 있는 데, 이 정도의 함수지원이면 충분해 보인다.




살다보니 한글 팁을 쓰게 될 줄은 몰랐네~ 오피스/VBA/Office.JS

워드프로세서 한글을 그닥 좋아하지 않는 편이다. 정보의 활용측면에서 문서를 테이터로 활용하기 어려운 점이 이유이다. 과거 문서의 지향점이 출력을 해서 보관을 하며 읽기 편하고 이쁜 문서 자체가 목적이었다. 워드프로세서 한글은 아직 예전의 목적에만 부합한다는 생각이 든다. 그러나 아직 그런 목적으로 워드프로세서를 필요로 하고 사용하는 곳이 있으니 선택과 취향의 문제이다.

워드프로세서 한글을 사용하면서 고정적인 서식작업(글꼴, 배경색, 글자색 등등)을 한번에 할 수 없나 싶어 기능을 살펴 보았다. 글꼴은 '함초롱바탕', 글자색은 '빨강', 배경색은 '검정' 을 선택하는 과정을 하나의 틀로 만들어 도장 찍듯이 하는 기능이 필요했는데, [글자 모양]대화상자에 그런 기능이 있어 팁을 남기게 되었다.
미리 원하는 서식을 선택한다. 그리고 [대화 상자 설정(/)]의 [구성]을 클릭한다.
[+]버튼을 클릭하여 앞서 만든 서식의 이름을 입력하고 저장한다.
이제 원하는 부분을 선택하고 [글자 모양]대화상자에서 [대화 상자 설정(/)]의 [사용자 지정]콤보를 클릭하여 앞서 만든 이름을 선택하면 끝
그런데 이 기능을 눈에 보이게 좀 만들면 좋을 텐데, 대화상자 끄트머리에 두었으니, 눈여겨 보지 않으면 모를 것 같다. 또 기능에 대한 이름도 직관적이지 못해 보인다. 대화상자 설정(?), 구성(?) 등등 무슨 기능인지 ...

(엑셀도감) 열린 통합문서 이동 오피스/VBA/Office.JS


(엑셀도감) 행과 열 선택하기 오피스/VBA/Office.JS


(엑셀도감) 시트이동 단축 키 오피스/VBA/Office.JS

    워크시트 이동 단축 키
  • CTRL+PgUp 왼쪽 시트로 이동
  • CTRL+PgDn 오른쪽 시트로 이동



라디안(radian)을 설명하면서... 삽질의 추억

각도와 라디안을 설명하면서 90도를 라디안으로 계산하는 과정을 보여주었다. 간단한 계산이지만, 하나의 개념을 두 가지 방식으로 사용하는 건 불편한 듯하다.
    핵심공식은
  • 원둘레=pi*원의 지름=pi*2*반지름
  • 라디안=호의 길이/반지름
이다.



(엑셀도감)날짜를 가지고 요일 표시하기 오피스/VBA/Office.JS


[활용] 날짜를 요일로 표시하기
[재료] TEXT()함수와 날짜
[설명]
TEXT(날짜, “aaa”) – 월, 화, 수, 목, 금, 토, 일
TEXT(날짜, “aaaa”) – 월요일, 화요일, 수요일, 목요일, 금요일, 토요일, 일요일


화폐의 시간가치 증권

금융 관련한 교육을 전혀 받지 못한 대학 신입생에게 재무관리수업의 시간가치, 미래가치라는 개념은 마냥 신기했다. 그리고 PV/ FV같은 간단한 공식이 단순히 해를 구하는 방정식이 아니라, 각 변수가 의미가 있는 것이라 이를 이해하는 게 나름 재미있었다.

Texas Instrument, HP의 공학/재무계산기를 이제 사용하지 않지만, 모태솔로라도 절로 즐거운 벚꽃이 흩날리는 봄에 이를 가지고 조작하다 보면 뭔가 대단한 걸 배우는 기분이 들었다. 이제는 그 계산기가 어디로 갔는 지 알 수 없고, PV/ FV는 더 이상 관심이 요즘 말로 1도 없다.

대신 파이썬에서 지원하는, 정확히는 Numpy와 Scipy같은 라이브러리가 지원하는 시간가치 관련 함수를 정리해 보고 싶었다. Scipy의 금융관련 함수는 numpy.lib.financial에서 가져 온 것이다. 금융관련 함수가 뭐가 있을 까...출석만 불러보면...
pv(),fv(),pmt(),npv(),rate(),nper(),irr(),mirr(),ipmt(),ppmt()

이어지는 내용

마지막 셀의 값을 가져오기 오피스/VBA/Office.JS

주가와 같은 시계열 데이터를 다루다 보면 데이터를 새로 업데이트 할 때, 기존 데이터 뒤에 추가하기 마련이다. 그런데 최신의 데이터를 보거나 사용하려다 보니, 매번 데이터의 위치가 달라져 최근 업데이트 한 셀을 참조하기 어려울 수 있다. 이때 사용가능한 함수가 OFFSET()인데, 이 함수가 뭐 하는 함수인가를 설명하려다 보니 '오프셋' 또는 '변위'라는 말이 쉽게 다가오지 않는다.

알고 보면 쉬운 것이지만 말로 하면 길어진다. 그래서 그림을 하나 만들어 보았는 데, 그림만 보고 빨리 이해할 수 있는 지 궁금하기도 하다.

    (업데이트) 올리고 보니 생각나는 몇 가지 문제점(자아비판, 자아성찰)
  • 번호가 없어 어디서 부터 봐야하지 모름
  • 라인과 설명이 너무 많아 복잡해 보임
  • 처음의 아이디어대로 개념만 잡는 단순한 그림으로 변경필요
그래서 아래와 같이 몇 가지 도안을 다시 만들어 보았다.





가지 말아야 할 길 자바스크립트

웹프로그래밍이 재미난 세상이라 엿보기를 하는 중인데, 웹프로그래밍에 입문해볼까 하는 사람들에게 좋은 길잡이가 있군요.
직업이 아니라서 다행인데, 이렇게 복잡할 줄 몰라네요. 기껏 아는 건 프론트엔드-백엔드 정도인데...
[URL]개발자로드맵


뜻밖의 손님 삽질의 추억


출근하자마자 PC를 켜니 처음 보는 손님이 내 바탕화면에 떡 하니 자리 잡고 앉아 있다. 얼마 전 소식을 듣긴 했는데, 우선은 이리 가가호호 방문하여 공지를 날려주는 MS님에게 감사.


그런데 OS만 오래된 것은 아니다. PC를 사용중인 인간도... 사용하는 PC사양은 처음 사용해보는 AMD CPU가 달린 조립컴(2012년 Mid, ㅎㅎ 어디서 애플 흉내를...)이다. 그래도 코어수가 많아서 아직은 사용할만 하다.


(보라~ 광활한 4G 메모리를 다스리는 저 위대하신 옥타코어님의 위엄을...)

MS가 몹쓸 물건으로 낙인 찍었지만 Win10이 나오기 전까진 그래도 가장 맘에 들어하는 OS이다.  이걸 핑계로 회사컴퓨터 좀 바꿔달라고 해야지...근데 회사가 사정이 그리 좋친 않아서

고인물같은 아주 오래된 잡기술 삽질의 추억

VBA와 달달하던 시절(여친이랑 그래야지, 고작 프로그램 따위랑 달달?)에 Userform에 차트를 보여주는 팁이 있었다. 그림이라 인터랙티브하진 않지만 거지같은 Userform에 이런 걸 보여줄 수 있다는 걸 만드는 게 웬지 뿌듯했다(그래봐야 남의 코드 베낀 거지만)

대단한 기술처럼 아끼던 잡기였지만 이제와 보니 쓸데없는 짓거리(애초에 오피스프로그래밍이 쓸데없는 짓이지만)이다. MS는 Userform을 띄워 뭔가 입력하고 보여주라고 Userform을 만들었겠지만 사용자 입장에선 거추장스러운 것이고(워크시트에서 하면 될 걸, 윈도 애플리케이션 같은 모양새 갖춘다고 그런 삽질을...) Userform과 관련 컨트롤들이 VB나 C#의 그것만큼 그닥 유용하지 않다.


근데 오늘은 이런 짓거리를 할 필요가 생겼다. 만드는 웹사이트(즉 웹프로그램)에 쬐맨한 차트를 보여주고 싶은 데, 엑셀의 스파크 라인이 탐나는 것이다. 20개 남짓한 차트를 한 눈에 볼 수 있게 보여 주기 위해 highcharts 같은 거 쓰는 건 낭비일 듯 하여 셀안에 저장한 스파크 라인을 그림파일로 만들어 보여주려는 아이디어이다.

그래서 작성한 코드가...
    Dim rng As Range
Dim pathName As String

Application.Calculation = xlCalculationManual

For Each rng In shNAV.Range(shNAV.Range("B3"), _
shNAV.Range("B3").End(xlToRight))

Set rng = rng.Offset(-1, 0)
rng.CopyPicture xlScreen, xlBitmap

With ActiveSheet.ChartObjects.Add(Left:=rng.Left, _
Top:=rng.Top, Width:=rng.Width, Height:=rng.Height)

.Name = "SparklineChartEXPORT"
.Activate
End With

''' Paste into chart area, export to file, delete chart.
pathName = "C:\apps\foo\foo\static\" & _
rng.Offset(2, 0).Value2 & ".jpg"

ActiveChart.Paste
With ActiveSheet.ChartObjects("SparklineChartEXPORT")
.Chart.Export pathName
.Delete
End With
Next
Application.Calculation = xlCalculationAutomatic
이다. 처음 돌려보니 속도가 아무래도 느리다. 그럴만 하다. 클립보드에 들어간 데이터를 차트를 만들어(그림으로 저장하기 위해 이용하는 것일 뿐) 붙여 넣고, 그림으로 추출하고 지우는 걸 반복하고 있기 때문이다. 재미있는 점은 속도를 올리기 위해 Application.ScreenUpdating 를 False로 주었더니 스파크 라인이 없는 빈 그림만 만들어 진다. 화면 렌더링을 꺼두었으니 그럴 만하다.

막상 웹페이지에 띄워보니 비트맵이라 흐릿하다. 흠 더구나 투명이미지 파일이 아니라서 테이블의 배경과도 어울리지 않는다. 원상복구를 고민한다. 근데 이 포스팅은 카테고리를 엑셀/VBA로 분류해야 하나...아님 삽질로 분류해야 하나...

[추가 속보]
검색을 하다보니 jQuery Sparklines이라 게 있다. 고민 끝이다. 일단 원상복구후 하고 싶을 때, jQuery Sparklines로 고고씽~

스택오버플로 설문 스택오버플로

vscode가 잘 나가는 군요. 첨엔 인쇄기능이 없어 당황했죠. (인쇄기능 없는 거 맞죠? 못찾는 거 아니고) 개인적으론 애정과 원한을 가진 병맛 vba가 objective c보다 한 단계 높은 데, 개찐도찐이네요. 잡스러운 언어! python이 java를 드디어 앞지르기 시작했는데, 자바스크립트의 17년 독재는 여전하네요. 자바스크립트를 제이쿼리 초기때까지만 하고 말다가 최근에 다시 시작했는데, 노드, 리액트, 앵귤러, 뷰 등 신예 프레임워크나 라이브러리를 보는 재미가 있어요.  아마 직업으로 삼았으면 징글징글하겠지만....






자세한 내용은  아래에서...




한국거래소 증권/파생상품시장 1차 제도개편 안내 증권


튜플을 쟁고 템플릿에서 출력하는 방법 스택오버플로

두 개의 쿼리셋을 합치는 방법(쿼리셋 병합이나 조인의 방법이 있지만, 시간이 많치 않아)이 마땅치 않아 결국 두 개를 zip()으로 묶어 리스트[ 튜플 ] 같은 형식으로 템플릿에 던지기로 했는 데, 막상 템플릿에서 풀어내기가 떠오르지 않는다.

스택오버플로에 나에 맞는 답변이 있어, 기록으로...정말 답변도 내가 해주고 싶은 게 그대로 있다.
How to do tuple unpacking in a template 'for' loop
mylst = [(a, b, c), (x, y, z), (l, m, n)]
{% for item in mylst %}    
     {{ item.0 }} {{ item.1}} {{ item.2 }}    
{% endfor %}
This is exactly what I was looking for, thanks.

무한의 노가다를 피하는 중... 삽질의 추억


아마추어 프로그래머이지만, 프로그래밍을 하다 보면 경험상 얻는 교훈이 있다. 그중에 하나는 이런 상황이다.
삽질의 추억
1. 코딩을 하다 문제가 생긴다
2. 문제해결을 위해 열심히 검색한다
3. 한 방에 정리되는 깔끔한 방법이 안보인다
4. 약간의 편법 또는 우회하는 방법으로 가령, 'M'을 동원한다
5. 'M'을 쓰려니 앞에 작성한 코드도 변경한다
6. 겨우 'M' 하나 쓰려고 몸집 좀 있는 다른 요소, 'P'가 필요하다

엑셀처럼 한 화면에 20개 정도의 펀드 기준가를 컬럼별로 출력하려고 하다가 현타가 온다
이 방법은 아닌 듯하다. 펀드가 50개가 되면 가독성은 어쩔려구..수 많은 펀드 기준가를 동시에 보여주는 게 무슨 의미가 있나...그냥 하나 또는 두 개의 정도 펀드기준가와 차트를 보여주는 게, 비교라는 명분이 생긴다.
암튼 이러다가 찾은 정보만...(쓸지는 않을 듯)

이렇게 억지로 끌려가는 느낌적인 느낌인 경우 그 결과물도 신통치 않다. 그러므로 발상의 전환과 이 부분의 코드는 새로 시작하는 게 좋다(잘 돌아가는 넘은 지우지 말고)

다음은 이렇게 삽질하여 찾은 검색의 결과들이다.
* pivoting (row/column transpose) in django template
* Displaying a Table in Django from Database
* Django-tables2
* Django에서 쿼리셋 효과적으로 사용하기
* Django DB data to HTML table
* (엑셀만큼 쉬운) Django Annotation/Aggregation
* django-pandas Documentation - django-pandas.pdf

또 나 혼자 코딩하고
나 혼자 디버깅하고
나 혼자 고민하고
이렇게 나 찾고 헤매고
소스파일은 저장없이 닫고 없어
후회해도 소용없어
오늘도 나 혼자
Whoo Whoo Whoo Whoo


GetObject()! 왜 거기서 나와? 오피스/VBA/Office.JS



외부파일을 읽어서 처리하는 경우 이미 열어 둔 상태라면 굳이 다시 열 필요는 없다. 이미 열어둔 상태라면 Workbooks()을 이용하여 WB28004 개체에 할당하게 된다.
Set WB28004 = Workbooks(fname)


그러나 열어 두지 않았다면 WB28004 개체는 Nothing이다. 그래서 만일 Nothing이라면 디스크에 저장된 파일을 열어야 한다. 경로명을 같이 주어 파일을 여는 데, Workbooks.Open()을 사용하지 않고 GetObject()를 이용한다. Workbooks.Open()은 이상하게 GetObject()보다 파일을 여는 속도가 느리다. 특히 큰 파일을 여는 경우 체감할 것이다.
Set WB28004 = GetObject(path & "\" & fname)


GetObject() 얘기는 여기까지만 하고, 다른 얘기를 하나 더 해본다. 아래는 실제 사용하는 코드인데, 파일 열기부터 애로사항이 봄꽃처럼 피는 상황이었다. 파일선택하는 [파일 열기]대화상자를 띄울 순 있지만, 사용자(내가 사용자이지만)는 그런 노가다를 좋아하지 않는다. 상황은 이렇다.

파일 이름이 만들어지는 규칙이 있는 데, 파일이름 끝에는 생성된 일자와 시간이 붙어 만들어 진다. 당일에 만들어 당일에 처리하는 상황이라 생성된 일자는 알 수 있지만, 생성되는 시간까지 고려해서 파일열기를 자동으로 만들 수 없다.

그래서 와일드카드 *(애스테리크, 전문용어로는 '별표') 이 포함된 파일명(경로포함)을 Dir()함수에 넘겨준다. 그런 파일이 없다면 아무 것도 돌려주지 않을 것이고, 그런 파일이 존재한다면 파일의 이름을 돌려줄 것이다. 즉 파일의 존재여부를 Dir()함수를 통해 찔러 보는 것이다.

    path = "C:\Users\gg6\Documents\Hints\Download\"
    fname = "28004_펀드별 수익률_2019_4_14_*.xlsx"
    dirFile = Dir(path & fname)
    If Len(dirFile) = 0 Then
        MsgBox "No file exists ", vbCritical, "File Error"
        Exit Sub
    End If

   
    On Error Resume Next
    Set WB28004 = Workbooks(dirFile)
    If WB28004 Is Nothing Then Set WB28004 = GetObject(path & dirFile)
   
    If WB28004 Is Nothing Then
        MsgBox "28004_ 파일을 열 수 없습니다. ", vbCritical, "파일 열기 에러"
        Exit Sub
    End If
    Err.Clear

    For Each rng In Range(작업영역)
        '//.. 작업처리(즉, 신나게 노가다)
        '//...... 작업처리(즉, 신나게 노가다)
        '//.......... 작업처리(즉, 신나게 노가다)
        '//............. 남의 신나는 노가다에는 관심이 없으실 것 같아 생략.
    Next

'// 그냥 읽어오는 용도이므로 단물빨고 저장하지 않고 버린다
    WB28004.Close SaveChanges:=False

'// 안해두면 엑셀에서는 파일은 닫혀 있는데, VBE에서 열린 것처럼 보인다.
'// 메모리에서 정리한다.
'// 즉 설겆이하는 것이다.
    Set WB28004 = Nothing


맥미니를 하나 들여 놓고... 삽질의 추억

지난 주말에 맥미니를 중고로 사서 다시 주말을 맞아 새로 셋팅을 하는 중이다. 오피스365, 아나콘다 설치하고 나니 달리 생각나는 게 없다. 혼자 차려 먹는 밥상만큼이나 단촐하다. vscode를 잊을 뻔 했네...

경로명+파일명에서 파일명만 가져오기

파일이름을 포함한 전체경로에서 파일명만 가져오는 자바스크립트 함수를 하나 만들었는데, 이 짜식이 첫 번째 경로만 실행한다.
<script type="text/javascript">
var getFilename = function (str) {
return str.split('\\').pop().split('/').pop();
}
var spans = document.getElementsByTagName('span');
for(var i=0; i<spans.length; i++){
console.log(spans[i].innerText)
spans[i].innerText = getFilename(spans[i].innerText);
}
</script>
흠 하나라도 제대로 실행되는 걸 보니, 함수의 문제는 아닌 듯하다. 생각해보니 스크립트의 위치가 상단인데, 아무래도 모든 html을 렌더링한 후 이 스크립트가 작동하는 것이 맞을 것 같아, 스크립트의 위치를 맨아래로 해보니 제대로 작동한다. 스크립트의 위치까지 고려해야 하다니...
다음은 span 태그속의 경로명+파일명중 파일명과 뽑아 다시 렌더링하는 예이다.
<html><head></head>
<body>
<span>C:\$Recycle.Bin</span>
<span>C:\bash.bat</span>
<span>C:\Config.Msi</span>
<span>C:\dirY.txt</span>
<span>C:\ErrTygem.txt</span>
<span>C:\ezCertIssuerCore.log</span>
<span>C:\hiberfil.sys</span>
<span>C:\nb.bat</span>
<span>C:\npchkaqua.dll</span>
<span>C:\pagefile.sys</span>
<span>C:\PDOXUSRS.NET</span>
<span>C:\rc4.log</span>
<span>C:\RHDSetup.log</span>
<span>C:\setup.log</span>
<span>C:\treeY.pdf</span>
<span>C:\treeY.txt</span>
<span>C:\treeZ.txt</span>

<script type="text/javascript">
var getFilename = function (str) {
return str.split('\\').pop().split('/').pop();
}
var spans = document.getElementsByTagName('span');
for(var i=0; i<spans.length; i++){
console.log(spans[i].innerText)
spans[i].innerText = getFilename(spans[i].innerText);
}
</script>
</body></html>

JSON 데이터 정렬 파이썬/쟁고

금감원 공시API를 이용하여 공시정보를 받아오는 데, 공시는 회사별로 받아오는 것이라서, 보유하고 있는 종목을 대상으로 하는 경우 그 결과가 당연히 회사위주로 받아 올 수 밖에 없다. 그러나 여러 회사의 공시를 받아 공시일자별로 보고자 하는 경우 수신받은 JSON을 정렬해야 한다. 그래서 아래의 코드를 예로 만들어 보았다.
gongsi=[
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160707', 'rcp_no': '20160707800438', 'rmk': '유', 'rpt_nm': '기업설명회(IR)개최(안내공시)'},
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '지완구', 'rcp_dt': '20160707', 'rcp_no': '20160707000087', 'rmk': '', 'rpt_nm': '임원ㆍ주요주주특정증권등소유상황보고서'},
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160615', 'rcp_no': '20160615800031', 'rmk': '유', 'rpt_nm': '풍문또는보도에대한해명'},
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160707', 'rcp_no': '20160707800065', 'rmk': '유', 'rpt_nm': '연결재무제표기준영업(잠정)실적(공정공시)'},
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160630', 'rcp_no': '20160630800581', 'rmk': '유', 'rpt_nm': '조회공시요구(풍문또는보도)에대한답변(부인)'},
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '이효건', 'rcp_dt': '20160629', 'rcp_no': '20160629000323', 'rmk': '', 'rpt_nm': '임원ㆍ주요주주특정증권등소유상황보고서'},
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '고홍선', 'rcp_dt': '20160615', 'rcp_no': '20160615000327', 'rmk': '', 'rpt_nm': '임원ㆍ주요주주특정증권등소유상황보고서'},
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '유가증권시장본부', 'rcp_dt': '20160630', 'rcp_no': '20160630800362', 'rmk': '유', 'rpt_nm': '조회공시요구(풍문또는보도)'},
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160613', 'rcp_no': '20160613800249', 'rmk': '유', 'rpt_nm': '최대주주등소유주식변동신고서'},
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160613', 'rcp_no': '20160613800234', 'rmk': '유', 'rpt_nm': '기업설명회(IR)개최(안내공시)'}
]
#reverse=False 는 오름차순 정렬
gongsi = sorted(gongsi, key=lambda k: k.get('rcp_dt', 0), reverse=False)
for g in gongsi:
    print(g)
===================== RESTART: C:/Python37/sortedJSON.py =====================
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160613', 'rcp_no': '20160613800249', 'rmk': '유', 'rpt_nm': '최대주주등소유주식변동신고서'}
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160613', 'rcp_no': '20160613800234', 'rmk': '유', 'rpt_nm': '기업설명회(IR)개최(안내공시)'}
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160615', 'rcp_no': '20160615800031', 'rmk': '유', 'rpt_nm': '풍문또는보도에대한해명'}
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '고홍선', 'rcp_dt': '20160615', 'rcp_no': '20160615000327', 'rmk': '', 'rpt_nm': '임원ㆍ주요주주특정증권등소유상황보고서'}
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '이효건', 'rcp_dt': '20160629', 'rcp_no': '20160629000323', 'rmk': '', 'rpt_nm': '임원ㆍ주요주주특정증권등소유상황보고서'}
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160630', 'rcp_no': '20160630800581', 'rmk': '유', 'rpt_nm': '조회공시요구(풍문또는보도)에대한답변(부인)'}
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '유가증권시장본부', 'rcp_dt': '20160630', 'rcp_no': '20160630800362', 'rmk': '유', 'rpt_nm': '조회공시요구(풍문또는보도)'}
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160707', 'rcp_no': '20160707800438', 'rmk': '유', 'rpt_nm': '기업설명회(IR)개최(안내공시)'}
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '지완구', 'rcp_dt': '20160707', 'rcp_no': '20160707000087', 'rmk': '', 'rpt_nm': '임원ㆍ주요주주특정증권등소유상황보고서'}
{'crp_cd': '005930', 'crp_cls': 'Y', 'crp_nm': '삼성전자', 'flr_nm': '삼성전자', 'rcp_dt': '20160707', 'rcp_no': '20160707800065', 'rmk': '유', 'rpt_nm': '연결재무제표기준영업(잠정)실적(공정공시)'}



다다익셀(多多益EXCEL) 오피스/VBA/Office.JS

보통 엑셀을 한번만 실행하고 사용하지만, 엑셀을 여러 개를 실행하는 경우가 있다(금수저가 아니어도 이 정도 사치는 부린다)
몇 개의 엑셀을 실행했는 지 확인하는 좋은 방법은 [Windows 작업 관리자]-[프로세스](Ctrl+Shift+Esc)를 보는 것이다.

위의 그림에선 EXCEL.EXE가 세 개 있는 걸 볼 수 있다. 이런 프로세스를 인스턴스라고 한다(인스턴트 라면 생각하지 마시고..) 프로그램은 디스크에 저장되어 있고, CPU는 실행명령을 받아 디스크를 읽어 메모리에 올린다. 이렇게 메모리에 올라간 것을 인스턴스라고 한다.

여러 개의 엑셀 인스턴스를 띄우려면
 [작업 표시줄]의 엑셀 아이콘에서 마우스 오른버튼을 클릭하고 [ALT]키를 누른 상태에서 엑셀아이콘을 클릭하면 된다(손가락이 아파도 아래의 대화상자가 나올 때 까지 참고 ALT키를 눌러준다) 그러면 아래와 같은 대화상자가 나온다.

VBE에서도 이렇게 인스턴스를 간접적으로 확인할 수 있는 데, 통합문서1,2,3,4와 ipostock.xlsm 등 5개의 파일을 열어 두었지만 VBE [프로젝트 탐색기]에서는 하나의 프로젝트만 있다. 즉 통합문서1,2,3,4는 ipostock.xlsm의 엑셀 인스턴스를 이용하지 않고 다른 인스턴스를 띄워 열어 놓은 것임을 알 수 있다.


64비트 오피스 아님 32비트 오피스 오피스/VBA/Office.JS

지금 사용하는 윈도는 64비트이지만, 사실 64비트 OS를 사용한 지는 그리 오래되지 않았다. 4기가 이상의 메모리를 모두 다 사용하려면 64비트 OS를 사용해야 한다.

그런데 OS만 64비트이지 아직은 32비트용 애플리케이션이 많다. 공기처럼 흔한 MS Office 역시 아직은 32비트 소프트웨어이다. 아직은 64비트 오피스가 무리인지 마이크로소프트도 32비트 오피스를 사용할 것을 권하고 오피스365에서 기본적인 다운로드 카피도 32비트용이다.

64비트 오피스와 32비트 오피스가 얼마나 차이가 있고, 64비트 오피스에 무슨 장점이 있는 지는 큰 관심은 없지만 프로그램을 만드는 입장에서 비트수에 따라 Win32API함수호출등과 같이 달리 처리해야 하는 경우가 있다.

다음은 그러한 예인데, #으로 시작하는 코드는 매크로 구문이다. 말 그대로 64비트인지 아닌 지를 확인하여 매개변수의 데이터형을 달리하는 함수를 선언하는 것이다.
#If Win64 Then
Private Function CheckHwnds(xlApps() As Application, hwnd As LongPtr) As Boolean
#Else
Private Function CheckHwnds(xlApps() As Application, hwnd As Long) As Boolean
#End If


Dim i As Long

On Error Resume Next

For i = LBound(xlApps) To UBound(xlApps)
If xlApps(i).hwnd = hwnd Then
CheckHwnds = False
Exit Function
End If
Next i

CheckHwnds = True

End Function


[파이썬 팁]천단위마다 컴마 붙이기 파이썬/쟁고

천단위마다 컴마를 찍는 방법중 최근에 본 팁이다.
num1=100000000000
num2=1000000000
total=num1+num2
print(f'{total:,}')

VBA 배열에 대한 한 가지 (4) 오피스/VBA/Office.JS

예전에 3부작 VBA배열 대하드라마(최수종씨는 안나온다)를 했는데, 이번에 하나 추가할 거리가 생겼다. 대단한 것은 아니고 활용도가 높다고 볼 수도 없는 팁이다(그럼! 하지마~)

가령 순차적으로 증가하는 배열을 만든다고 하면, 일단 배열을 선언하고 루프를 돌려 배열을 채울 것이다.
    a(0) = 1
a(1) = 2
a(2) = 3
a(3) = 4
a(4) = 5

' 혹은

For i = 0 To 4
a(i) = i + 1
Next
아무리 코드를 간단히 해도 루프문을 사용하는 것이 아직은 최선이다. 하지만 VBA가 아닌 엑셀의 힘을 빌리면 더 최선이 된다. 다음의 코드를 보자.
    b = WorksheetFunction.Transpose(Evaluate("=ROW(1:5)"))
ROW()함수를 사용하면 내부적으로 1,2,3,4,5의 원소를 갖는 배열이 생긴다. 이 식을 문자열이 아닌 연산으로 처리하기 위해 Evaluate()를 사용한다.
그러나 배열은 쓸데없이 2차원 배열이라 액세스하기 영 불편하다. 그래서 VBA판 워크시트함수인 WorksheetFunction.Transpose()를 동원하여 1차원 배열로 살짝 틀어준다.
    b = WorksheetFunction.Transpose(Evaluate("=ROW(1:5)"))
위의 코드가 어쩌면 쓸모가 없으지도 모르지만, 그래도 토착왜구같은 국회의원보단 쓸모가 있을 것이다.

1 2 3 4 5 6 7 8 9 10 다음